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 +++++++++++++++++++++++++++++++++++++++++- src/checker_builtin_procs.hpp | 10 ++- 2 files changed, 147 insertions(+), 2 deletions(-) (limited to 'src') 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) { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index c89ab2429..c5d10955b 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -260,6 +260,10 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_is_specialization_of, BuiltinProc_type_is_variant_of, + BuiltinProc_type_union_tag, + BuiltinProc_type_union_tag_offset, + BuiltinProc_type_variant_type, + BuiltinProc_type_variant_tag, BuiltinProc_type_struct_field_count, @@ -557,7 +561,11 @@ 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_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_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_type"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_tag"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From c76ab138eb574f271dff7b029ee8df2a1a6c7481 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Tue, 24 Oct 2023 22:15:33 +0200 Subject: Naming, use variant index instead of tag --- core/intrinsics/intrinsics.odin | 5 +++++ src/checker_builtin_procs.hpp | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 33c4e2b07..505309a8e 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -162,7 +162,12 @@ type_is_matrix :: proc($T: typeid) -> bool --- 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_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_index_of :: proc($U, $V: typeid) -> int where type_is_union(U) --- type_has_field :: proc($T: typeid, $name: string) -> bool --- type_field_type :: proc($T: typeid, $name: string) -> typeid --- diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index c5d10955b..8053d54f2 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -262,8 +262,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_is_variant_of, BuiltinProc_type_union_tag, BuiltinProc_type_union_tag_offset, - BuiltinProc_type_variant_type, - BuiltinProc_type_variant_tag, + BuiltinProc_type_variant_type_of, + BuiltinProc_type_variant_index_of, BuiltinProc_type_struct_field_count, @@ -564,8 +564,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {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_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_variant_type"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_variant_tag"), 2, 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 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') 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') 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') 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') 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 e19460cbd7c847bd5452b2c7bf96b38d06b2a182 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 10 Nov 2023 19:37:08 +0100 Subject: Add -microarch:? --- build.bat | 1 + src/build_settings.cpp | 19 +++++++++++++++++-- src/llvm_backend.cpp | 7 +++++++ src/main.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/string.cpp | 24 ++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/build.bat b/build.bat index b0ebfe634..41e32f5ed 100644 --- a/build.bat +++ b/build.bat @@ -110,6 +110,7 @@ if %errorlevel% neq 0 goto end_of_build call build_vendor.bat if %errorlevel% neq 0 goto end_of_build +rem If the demo doesn't run for you and your CPU is more than a decade old, try -microarch:native if %release_mode% EQU 0 odin run examples/demo del *.obj > NUL 2> NUL diff --git a/src/build_settings.cpp b/src/build_settings.cpp index ffb276d1e..b9b591a7f 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -82,6 +82,23 @@ gb_global String target_arch_names[TargetArch_COUNT] = { str_lit("wasm64p32"), }; +gb_global String target_microarch_list[TargetArch_COUNT] = { + // TargetArch_Invalid, + str_lit("Invalid!"), + // TargetArch_amd64, + str_lit("alderlake,amdfam10,athlon-fx,athlon64,athlon64-sse3,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,broadwell,btver1,btver2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,generic,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k8,k8-sse3,knl,knm,meteorlake,mic_avx512,native,nehalem,nocona,opteron,opteron-sse3,penryn,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,x86-64,x86-64-v2 (default),x86-64-v3,x86-64-v4,znver1,znver2,znver3,znver4"), + // TargetArch_i386, + str_lit("athlon,athlon-4,athlon-mp,athlon-tbird,athlon-xp,atom,bonnell,c3,c3-2,generic (default),geode,i386,i486,i586,i686,k6,k6-2,k6-3,lakemont,native,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,winchip-c6,winchip2,yonah"), + // TargetArch_arm32, + str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic (default),iwmmxt,krait,kryo,mpcore,mpcorenovfp,native,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"), + // TargetArch_arm64, + str_lit("a64fx,ampere1,ampere1a,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a8,apple-a9,apple-latest,apple-m1,apple-m2,apple-s4,apple-s5,carmel,cortex-a34,cortex-a35,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-r82,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,generic (default),kryo,native,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), + // TargetArch_wasm32, + str_lit("generic (default)"), + // TargetArch_wasm64p32, + str_lit("generic (default)"), +}; + gb_global String target_endian_names[TargetEndian_COUNT] = { str_lit("little"), str_lit("big"), @@ -109,8 +126,6 @@ gb_global TargetEndianKind target_endians[TargetArch_COUNT] = { gb_global String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW); - - struct TargetMetrics { TargetOsKind os; TargetArchKind arch; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 276abc2d4..707ef2969 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2518,6 +2518,13 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } } + // NOTE(Jeroen): Uncomment to get the list of supported microarchitectures. + /* + if (build_context.microarch == "?") { + string_set_add(&build_context.target_features_set, str_lit("+cpuhelp")); + } + */ + if (build_context.target_features_set.entries.count != 0) { llvm_features = target_features_set_to_cstring(permanent_allocator(), false); } diff --git a/src/main.cpp b/src/main.cpp index 79c2b3561..8a917090b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2518,6 +2518,45 @@ int main(int arg_count, char const **arg_ptr) { // return 1; // } + // Check chosen microarchitecture. If not found or ?, print list. + bool print_microarch_list = true; + if (build_context.microarch.len == 0) { + // Autodetect, no need to print list. + print_microarch_list = false; + } else { + String march_list = target_microarch_list[build_context.metrics.arch]; + String_Iterator it = {march_list, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + // If it's the entry in the list marked (default), we strip off the suffix before the match. + if (string_ends_with(str, str_lit(" (default)"))) { + str = substring(str, 0, str.len - 10); + } + if (str == build_context.microarch) { + // Found matching microarch + print_microarch_list = false; + } + } + } + + if (print_microarch_list) { + if (build_context.microarch != "?") { + gb_printf("Unknown microarchitecture '%.*s'.\n", LIT(build_context.microarch)); + } + gb_printf("Possible -microarch values for target %.*s are:\n", LIT(target_arch_names[build_context.metrics.arch])); + gb_printf("\n"); + + String march_list = target_microarch_list[build_context.metrics.arch]; + String_Iterator it = {march_list, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + gb_printf("\t%.*s\n", LIT(str)); + } + return 0; + } + // Set and check build paths... if (!init_build_paths(init_filename)) { return 1; diff --git a/src/string.cpp b/src/string.cpp index 6eac4f53b..e85787c59 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -10,6 +10,10 @@ struct String { return text[i]; } }; +struct String_Iterator { + String const &str; + isize pos; +}; // NOTE(bill): used for printf style arguments #define LIT(x) ((int)(x).len), (x).text #if defined(GB_COMPILER_MSVC) && _MSC_VER < 1700 @@ -201,6 +205,26 @@ gb_internal gb_inline String string_trim_starts_with(String const &s, String con } +gb_internal String string_split_iterator(String_Iterator *it, const char sep) { + isize start = it->pos; + isize end = it->str.len; + + if (start == end) { + return str_lit(""); + } + + isize i = start; + for (; i < it->str.len; i++) { + if (it->str[i] == sep) { + String res = substring(it->str, start, i); + it->pos += res.len + 1; + return res; + } + } + it->pos = end; + return substring(it->str, start, end); +} + gb_internal gb_inline isize string_extension_position(String const &str) { isize dot_pos = -1; isize i = str.len; -- cgit v1.2.3 From f9039510167c50e0a86e4c25fad5aa08aca24bf0 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 10 Nov 2023 20:14:00 +0100 Subject: Facored out `get_default_microarchitecture` Moved `generic` -> `x86-64-v2` selection into its own procedure so that `llvm_backend.cpp` and `main.cpp` can share the same logic. --- src/build_settings.cpp | 13 ++++++------- src/llvm_backend.cpp | 35 ++++++++++++++++++++--------------- src/main.cpp | 15 +++++++++------ 3 files changed, 35 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index b9b591a7f..94807a852 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -86,17 +86,17 @@ gb_global String target_microarch_list[TargetArch_COUNT] = { // TargetArch_Invalid, str_lit("Invalid!"), // TargetArch_amd64, - str_lit("alderlake,amdfam10,athlon-fx,athlon64,athlon64-sse3,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,broadwell,btver1,btver2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,generic,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k8,k8-sse3,knl,knm,meteorlake,mic_avx512,native,nehalem,nocona,opteron,opteron-sse3,penryn,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,x86-64,x86-64-v2 (default),x86-64-v3,x86-64-v4,znver1,znver2,znver3,znver4"), + str_lit("alderlake,amdfam10,athlon-fx,athlon64,athlon64-sse3,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,broadwell,btver1,btver2,cannonlake,cascadelake,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,generic,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k8,k8-sse3,knl,knm,meteorlake,mic_avx512,native,nehalem,nocona,opteron,opteron-sse3,penryn,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,znver1,znver2,znver3,znver4"), // TargetArch_i386, - str_lit("athlon,athlon-4,athlon-mp,athlon-tbird,athlon-xp,atom,bonnell,c3,c3-2,generic (default),geode,i386,i486,i586,i686,k6,k6-2,k6-3,lakemont,native,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,winchip-c6,winchip2,yonah"), + str_lit("athlon,athlon-4,athlon-mp,athlon-tbird,athlon-xp,atom,bonnell,c3,c3-2,generic,geode,i386,i486,i586,i686,k6,k6-2,k6-3,lakemont,native,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,winchip-c6,winchip2,yonah"), // TargetArch_arm32, - str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic (default),iwmmxt,krait,kryo,mpcore,mpcorenovfp,native,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"), + str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic,iwmmxt,krait,kryo,mpcore,mpcorenovfp,native,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"), // TargetArch_arm64, - str_lit("a64fx,ampere1,ampere1a,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a8,apple-a9,apple-latest,apple-m1,apple-m2,apple-s4,apple-s5,carmel,cortex-a34,cortex-a35,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-r82,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,generic (default),kryo,native,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), + str_lit("a64fx,ampere1,ampere1a,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a8,apple-a9,apple-latest,apple-m1,apple-m2,apple-s4,apple-s5,carmel,cortex-a34,cortex-a35,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-r82,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,generic,kryo,native,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), // TargetArch_wasm32, - str_lit("generic (default)"), + str_lit("generic"), // TargetArch_wasm64p32, - str_lit("generic (default)"), + str_lit("generic"), }; gb_global String target_endian_names[TargetEndian_COUNT] = { @@ -638,7 +638,6 @@ gb_internal TargetArchKind get_target_arch_from_string(String str) { return TargetArch_Invalid; } - gb_internal bool is_excluded_target_filename(String name) { String original_name = name; name = remove_extension_from_path(name); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 707ef2969..effd9d28e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -21,6 +21,25 @@ #include "llvm_backend_stmt.cpp" #include "llvm_backend_proc.cpp" +char *get_default_microarchitecture() { + char * default_march = "generic"; + if (build_context.metrics.arch == TargetArch_amd64) { + // NOTE(bill): x86-64-v2 is more than enough for everyone + // + // x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2 + // x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3 + // x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE + // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL + if (ODIN_LLVM_MINIMUM_VERSION_12) { + if (build_context.metrics.os == TargetOs_freestanding) { + default_march = "x86-64"; + } else { + default_march = "x86-64-v2"; + } + } + } + return default_march; +} gb_internal void lb_add_foreign_library_path(lbModule *m, Entity *e) { if (e == nullptr) { @@ -2491,7 +2510,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } char const *host_cpu_name = LLVMGetHostCPUName(); - char const *llvm_cpu = "generic"; + char const *llvm_cpu = get_default_microarchitecture(); char const *llvm_features = ""; if (build_context.microarch.len != 0) { if (build_context.microarch == "native") { @@ -2502,20 +2521,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { if (gb_strcmp(llvm_cpu, host_cpu_name) == 0) { llvm_features = LLVMGetHostCPUFeatures(); } - } else if (build_context.metrics.arch == TargetArch_amd64) { - // NOTE(bill): x86-64-v2 is more than enough for everyone - // - // x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2 - // x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3 - // x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE - // x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL - if (ODIN_LLVM_MINIMUM_VERSION_12) { - if (build_context.metrics.os == TargetOs_freestanding) { - llvm_cpu = "x86-64"; - } else { - llvm_cpu = "x86-64-v2"; - } - } } // NOTE(Jeroen): Uncomment to get the list of supported microarchitectures. diff --git a/src/main.cpp b/src/main.cpp index 8a917090b..bf91a0889 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2529,10 +2529,6 @@ int main(int arg_count, char const **arg_ptr) { for (;;) { String str = string_split_iterator(&it, ','); if (str == "") break; - // If it's the entry in the list marked (default), we strip off the suffix before the match. - if (string_ends_with(str, str_lit(" (default)"))) { - str = substring(str, 0, str.len - 10); - } if (str == build_context.microarch) { // Found matching microarch print_microarch_list = false; @@ -2547,12 +2543,19 @@ int main(int arg_count, char const **arg_ptr) { gb_printf("Possible -microarch values for target %.*s are:\n", LIT(target_arch_names[build_context.metrics.arch])); gb_printf("\n"); - String march_list = target_microarch_list[build_context.metrics.arch]; + String march_list = target_microarch_list[build_context.metrics.arch]; String_Iterator it = {march_list, 0}; + + String default_march = make_string_c(get_default_microarchitecture()); + for (;;) { String str = string_split_iterator(&it, ','); if (str == "") break; - gb_printf("\t%.*s\n", LIT(str)); + if (str == default_march) { + gb_printf("\t%.*s (default)\n", LIT(str)); + } else { + gb_printf("\t%.*s\n", LIT(str)); + } } return 0; } -- cgit v1.2.3 From f6f4734fee4fb253bc7c16410790e97955a72a1e Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 10 Nov 2023 20:22:20 +0100 Subject: Re-add `break`. --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index bf91a0889..59bed1e54 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2532,6 +2532,7 @@ int main(int arg_count, char const **arg_ptr) { if (str == build_context.microarch) { // Found matching microarch print_microarch_list = false; + break; } } } -- cgit v1.2.3 From 086478e8f20ac9633daaf2e3485ef7778ee82441 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 11 Nov 2023 02:34:59 +0100 Subject: fix -test-name flag --- src/checker.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 29f22bd9c..9653116cf 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -6091,9 +6091,6 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("calculate global init order"); calculate_global_init_order(c); - TIME_SECTION("check test procedures"); - check_test_procedures(c); - TIME_SECTION("add type info for type definitions"); add_type_info_for_type_definitions(c); check_merge_queues_into_arrays(c); @@ -6104,6 +6101,11 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("generate minimum dependency set"); generate_minimum_dependency_set(c, c->info.entry_point); + // NOTE(laytan): has to be ran after generate_minimum_dependency_set, + // because that collects the test procedures. + TIME_SECTION("check test procedures"); + check_test_procedures(c); + TIME_SECTION("check bodies have all been checked"); check_unchecked_bodies(c); -- cgit v1.2.3 From 0ca39c70a51b6f8236c30e010af045303739dbeb Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 11 Nov 2023 13:07:12 +0100 Subject: Add -microarch:? to help text. --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 59bed1e54..b8abe94f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1876,6 +1876,7 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Examples:"); print_usage_line(3, "-microarch:sandybridge"); print_usage_line(3, "-microarch:native"); + print_usage_line(3, "-microarch:? for a list"); print_usage_line(0, ""); print_usage_line(1, "-reloc-mode:"); -- cgit v1.2.3 From 9e5e49a65daf1f189e49c0eade7d90d148e7ac71 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 14 Nov 2023 16:53:30 +0100 Subject: checker: suggest ..[]T when passing a slice to variadic arg ..T --- src/check_expr.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5cc548739..5a8b57df6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5652,6 +5652,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } else { if (show_error) { check_assignment(c, o, param_type, str_lit("procedure argument")); + + Type *src = base_type(o->type); + Type *dst = base_type(param_type); + if (is_type_slice(src) && are_types_identical(src->Slice.elem, dst)) { + gbString a = expr_to_string(o->expr); + error_line("\tSuggestion: Did you mean to pass the slice into the variadic parameter with ..%s?\n\n", a); + gb_string_free(a); + } } err = CallArgumentError_WrongTypes; } -- cgit v1.2.3 From 6b9202dfbf25a022287583197e57dbcd9159ea63 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sun, 12 Nov 2023 02:02:30 +0100 Subject: -no-crt and assembly compilation on darwin --- core/runtime/entry_unix.odin | 11 ++++--- core/runtime/entry_unix_no_crt_darwin_arm64.asm | 20 ++++++++++++ core/runtime/os_specific_any.odin | 2 +- core/runtime/os_specific_darwin.odin | 12 +++++++ src/checker.cpp | 2 +- src/linker.cpp | 42 ++++++++++++++++--------- 6 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 core/runtime/entry_unix_no_crt_darwin_arm64.asm create mode 100644 core/runtime/os_specific_darwin.odin (limited to 'src') diff --git a/core/runtime/entry_unix.odin b/core/runtime/entry_unix.odin index 0c718445a..78e545c22 100644 --- a/core/runtime/entry_unix.odin +++ b/core/runtime/entry_unix.odin @@ -26,8 +26,13 @@ when ODIN_BUILD_MODE == .Dynamic { // to retrieve argc and argv from the stack when ODIN_ARCH == .amd64 { @require foreign import entry "entry_unix_no_crt_amd64.asm" + SYS_exit :: 60 } else when ODIN_ARCH == .i386 { @require foreign import entry "entry_unix_no_crt_i386.asm" + SYS_exit :: 1 + } else when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 { + @require foreign import entry "entry_unix_no_crt_darwin_arm64.asm" + SYS_exit :: 1 } @(link_name="_start_odin", linkage="strong", require) _start_odin :: proc "c" (argc: i32, argv: [^]cstring) -> ! { @@ -36,11 +41,7 @@ when ODIN_BUILD_MODE == .Dynamic { #force_no_inline _startup_runtime() intrinsics.__entry_point() #force_no_inline _cleanup_runtime() - when ODIN_ARCH == .amd64 { - intrinsics.syscall(/*SYS_exit = */60) - } else when ODIN_ARCH == .i386 { - intrinsics.syscall(/*SYS_exit = */1) - } + intrinsics.syscall(SYS_exit, 0) unreachable() } } else { diff --git a/core/runtime/entry_unix_no_crt_darwin_arm64.asm b/core/runtime/entry_unix_no_crt_darwin_arm64.asm new file mode 100644 index 000000000..0f71fbdf8 --- /dev/null +++ b/core/runtime/entry_unix_no_crt_darwin_arm64.asm @@ -0,0 +1,20 @@ + .section __TEXT,__text + + ; NOTE(laytan): this should ideally be the -minimum-os-version flag but there is no nice way of preprocessing assembly in Odin. + ; 10 seems to be the lowest it goes and I don't see it mess with any targeted os version so this seems fine. + .build_version macos, 10, 0 + + .extern __start_odin + + .global _main + .align 2 +_main: + mov x5, sp ; use x5 as the stack pointer + + str x0, [x5] ; get argc into x0 (kernel passes 32-bit int argc as 64-bits on stack to keep alignment) + str x1, [x5, #8] ; get argv into x1 + + and sp, x5, #~15 ; force 16-byte alignment of the stack + + bl __start_odin ; call into Odin entry point + ret ; should never get here diff --git a/core/runtime/os_specific_any.odin b/core/runtime/os_specific_any.odin index afa106138..5fffceeeb 100644 --- a/core/runtime/os_specific_any.odin +++ b/core/runtime/os_specific_any.odin @@ -1,4 +1,4 @@ -//+build !freestanding !wasi !windows !js +//+build !freestanding !wasi !windows !js !darwin package runtime import "core:os" diff --git a/core/runtime/os_specific_darwin.odin b/core/runtime/os_specific_darwin.odin new file mode 100644 index 000000000..33136c92f --- /dev/null +++ b/core/runtime/os_specific_darwin.odin @@ -0,0 +1,12 @@ +//+build darwin +package runtime + +import "core:intrinsics" + +_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) { + ret := intrinsics.syscall(4, 1, uintptr(raw_data(data)), uintptr(len(data))) + if ret < 0 { + return 0, _OS_Errno(-ret) + } + return int(ret), 0 +} diff --git a/src/checker.cpp b/src/checker.cpp index 29f22bd9c..0366cf05d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4733,7 +4733,7 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { } if (has_asm_extension(fullpath)) { - if (build_context.metrics.arch != TargetArch_amd64) { + if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.os != TargetOs_darwin) { error(decl, "Assembly files are not yet supported on this platform: %.*s_%.*s", LIT(target_os_names[build_context.metrics.os]), LIT(target_arch_names[build_context.metrics.arch])); } diff --git a/src/linker.cpp b/src/linker.cpp index eb3687ae2..c3ede0f55 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -337,20 +337,34 @@ gb_internal i32 linker_stage(LinkerData *gen) { obj_format = str_lit("elf32"); } #endif // GB_ARCH_*_BIT - // Note(bumbread): I'm assuming nasm is installed on the host machine. - // Shipping binaries on unix-likes gets into the weird territorry of - // "which version of glibc" is it linked with. - result = system_exec_command_line_app("nasm", - "nasm \"%.*s\" " - "-f \"%.*s\" " - "-o \"%.*s\" " - "%.*s " - "", - LIT(asm_file), - LIT(obj_format), - LIT(obj_file), - LIT(build_context.extra_assembler_flags) - ); + + if (is_osx) { + // `as` comes with MacOS. + result = system_exec_command_line_app("as", + "as \"%.*s\" " + "-o \"%.*s\" " + "%.*s " + "", + LIT(asm_file), + LIT(obj_file), + LIT(build_context.extra_assembler_flags) + ); + } else { + // Note(bumbread): I'm assuming nasm is installed on the host machine. + // Shipping binaries on unix-likes gets into the weird territorry of + // "which version of glibc" is it linked with. + result = system_exec_command_line_app("nasm", + "nasm \"%.*s\" " + "-f \"%.*s\" " + "-o \"%.*s\" " + "%.*s " + "", + LIT(asm_file), + LIT(obj_format), + LIT(obj_file), + LIT(build_context.extra_assembler_flags) + ); + } array_add(&gen->output_object_paths, obj_file); } else { if (string_set_update(&libs, lib)) { -- cgit v1.2.3 From d9fab5e824b5caee48ed96cf76e0011f0cdf6742 Mon Sep 17 00:00:00 2001 From: Paco Pascal Date: Sat, 18 Nov 2023 20:56:22 -0500 Subject: Return value of _umtx_op on FreeBSD wasn't checked correctly --- src/threading.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/threading.cpp b/src/threading.cpp index 3ddc05b0a..74aa3eb7e 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -660,7 +660,7 @@ gb_internal void futex_broadcast(Futex *addr) { gb_internal void futex_wait(Futex *addr, Footex val) { for (;;) { int ret = _umtx_op(addr, UMTX_OP_WAIT_UINT, val, 0, NULL); - if (ret == 0) { + if (ret == -1) { if (errno == ETIMEDOUT || errno == EINTR) { continue; } -- cgit v1.2.3 From 25e92551578466548584cfa9d4a2db25de9c6248 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 21 Nov 2023 16:53:14 +0100 Subject: Fix `string_extension_position` --- src/string.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.cpp b/src/string.cpp index 6eac4f53b..9d7ff7b89 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -205,7 +205,7 @@ gb_internal gb_inline isize string_extension_position(String const &str) { isize dot_pos = -1; isize i = str.len; while (i --> 0) { - if (str[i] == GB_PATH_SEPARATOR) + if (str[i] == '\\' || str[i] == '/') break; if (str[i] == '.') { dot_pos = i; -- cgit v1.2.3 From 4c1a9d2b3f821733ac79135c76e13d3be6f3ed4f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 23 Nov 2023 16:56:18 +0000 Subject: Fix `&x[i]` of `^#soa` types --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5a8b57df6..7b90677c8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2339,7 +2339,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * ast_node(ue, UnaryExpr, node); if (ast_node_expect(ue->expr, Ast_IndexExpr)) { ast_node(ie, IndexExpr, ue->expr); - Type *soa_type = type_of_expr(ie->expr); + Type *soa_type = type_deref(type_of_expr(ie->expr)); GB_ASSERT(is_type_soa_struct(soa_type)); o->type = alloc_type_soa_pointer(soa_type); } else { @@ -7428,7 +7428,7 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count = t->Struct.soa_count; } o->type = t->Struct.soa_elem; - if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable) { + if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable || indirection) { o->mode = Addressing_SoaVariable; } else { o->mode = Addressing_Value; -- 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') 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 e78ee90ac229468e88281fece02b752cc8160744 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Thu, 23 Nov 2023 20:58:26 +0100 Subject: Remove code that skipped checking blank params --- src/check_expr.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7b90677c8..71accfb81 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5606,9 +5606,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A for (isize i = 0; i < pt->param_count; i++) { if (!visited[i]) { Entity *e = pt->params->Tuple.variables[i]; - if (is_blank_ident(e->token)) { - continue; - } if (e->kind == Entity_Variable) { if (e->Variable.param_value.kind != ParameterValue_Invalid) { ordered_operands[i].mode = Addressing_Value; -- cgit v1.2.3 From 3102abf1aabdfff798cc0d2020c07c7138b59648 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 24 Nov 2023 10:57:18 +0000 Subject: mem zero rather than store to a union where the variant is of size zero --- src/llvm_backend.hpp | 1 + src/llvm_backend_general.cpp | 12 +++++++++--- src/llvm_backend_utility.cpp | 4 ++++ 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 5894dd38a..3e4070367 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -550,6 +550,7 @@ gb_internal LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLV gb_internal void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false); gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false); gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile); +gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, usize len, unsigned alignment, bool is_volatile); gb_internal gb_inline i64 lb_max_zero_init_size(void) { return cast(i64)(4*build_context.int_size); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index fdcf94f29..c149ec853 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1332,6 +1332,8 @@ gb_internal void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbV Type *pt = base_type(type_deref(parent.type)); GB_ASSERT(pt->kind == Type_Union); if (pt->Union.kind == UnionType_shared_nil) { + GB_ASSERT(type_size_of(variant_type)); + lbBlock *if_nil = lb_create_block(p, "shared_nil.if_nil"); lbBlock *if_not_nil = lb_create_block(p, "shared_nil.if_not_nil"); lbBlock *done = lb_create_block(p, "shared_nil.done"); @@ -1353,9 +1355,13 @@ gb_internal void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbV } else { - lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); - - lb_emit_store(p, underlying, variant); + if (type_size_of(variant_type) == 0) { + unsigned alignment = 1; + lb_mem_zero_ptr_internal(p, parent.value, pt->Union.variant_block_size, alignment, false); + } else { + lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); + lb_emit_store(p, underlying, variant); + } lb_emit_store_union_variant_tag(p, parent, variant_type); } } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index d8dbfd736..be3ae9c8a 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -57,6 +57,10 @@ gb_internal lbValue lb_correct_endianness(lbProcedure *p, lbValue value) { return value; } +gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, usize len, unsigned alignment, bool is_volatile) { + return lb_mem_zero_ptr_internal(p, ptr, LLVMConstInt(lb_type(p->module, t_uint), len, false), alignment, is_volatile); +} + gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) { bool is_inlinable = false; -- cgit v1.2.3 From c12eb3ec933b2415b5d6ca12e173b1fac8c3c847 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 24 Nov 2023 11:44:20 +0000 Subject: Improve returning a struct directly for certain ABIs; reuse the temp callee return struct memory when needed --- src/llvm_backend.hpp | 2 ++ src/llvm_backend_stmt.cpp | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 3e4070367..4e193bcea 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -339,6 +339,8 @@ struct lbProcedure { bool in_multi_assignment; Array raw_input_parameters; + LLVMValueRef temp_callee_return_struct_memory; + Ast *curr_stmt; Array scope_stack; diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 9d688be6a..002fef881 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1846,9 +1846,25 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { LLVMBuildRetVoid(p->builder); } else { LLVMValueRef ret_val = res.value; - ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.type); - if (p->abi_function_type->ret.cast_type != nullptr) { - ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.cast_type); + LLVMTypeRef ret_type = p->abi_function_type->ret.type; + if (LLVMTypeRef cast_type = p->abi_function_type->ret.cast_type) { + ret_type = cast_type; + } + + if (LLVMGetTypeKind(ret_type) == LLVMStructTypeKind) { + LLVMTypeRef src_type = LLVMTypeOf(ret_val); + + if (p->temp_callee_return_struct_memory == nullptr) { + i64 max_align = gb_max(lb_alignof(ret_type), lb_alignof(src_type)); + p->temp_callee_return_struct_memory = llvm_alloca(p, ret_type, max_align); + } + // reuse the temp return value memory where possible + LLVMValueRef ptr = p->temp_callee_return_struct_memory; + LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), ""); + LLVMBuildStore(p->builder, ret_val, nptr); + ret_val = LLVMBuildLoad2(p->builder, ret_type, ptr, ""); + } else { + ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type); } lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); -- cgit v1.2.3 From 914950592cd05445d5f9b42fb6cf459a002f21fc Mon Sep 17 00:00:00 2001 From: Tarık B Date: Fri, 24 Nov 2023 14:56:55 +0100 Subject: Fix indentation --- src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index b8abe94f4..ccacf168a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1945,9 +1945,9 @@ gb_internal void print_show_help(String const arg0, String const &command) { if (run_or_build) { print_usage_line(1, "-sanitize:"); - print_usage_line(1, "Enables sanitization analysis"); - print_usage_line(1, "Options are 'address', 'memory', and 'thread'"); - print_usage_line(1, "NOTE: This flag can be used multiple times"); + print_usage_line(2, "Enables sanitization analysis"); + print_usage_line(2, "Options are 'address', 'memory', and 'thread'"); + print_usage_line(2, "NOTE: This flag can be used multiple times"); print_usage_line(0, ""); } -- cgit v1.2.3 From 70525a12cadcfa45ea78522c8003227d27f4847b Mon Sep 17 00:00:00 2001 From: Tarık B Date: Fri, 24 Nov 2023 20:42:11 +0100 Subject: Fix typo --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index ccacf168a..066a86fb8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1938,7 +1938,7 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-foreign-error-procedures"); - print_usage_line(2, "States that the error procedues used in the runtime are defined in a separate translation unit"); + print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit"); print_usage_line(0, ""); } -- cgit v1.2.3 From 6f65ed6cc81318aa22b8aa6709a5eb22ecf8226b Mon Sep 17 00:00:00 2001 From: Tarık B Date: Fri, 24 Nov 2023 21:49:23 +0100 Subject: Add period at the end of sentences. --- src/main.cpp | 208 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 104 insertions(+), 104 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 066a86fb8..ab1fdda91 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -199,19 +199,19 @@ gb_internal void print_usage_line(i32 indent, char const *fmt, ...) { } gb_internal void usage(String argv0) { - print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(argv0)); + print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(argv0)); print_usage_line(0, "Usage:"); print_usage_line(1, "%.*s command [arguments]", LIT(argv0)); print_usage_line(0, "Commands:"); print_usage_line(1, "build compile directory of .odin files, as an executable."); print_usage_line(1, " one must contain the program's entry point, all must be in the same package."); print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable."); - print_usage_line(1, "check parse, and type check a directory of .odin files"); - print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program"); - print_usage_line(1, "test build and runs procedures with the attribute @(test) in the initial package"); - print_usage_line(1, "doc generate documentation on a directory of .odin files"); - print_usage_line(1, "version print version"); - print_usage_line(1, "report print information useful to reporting a bug"); + print_usage_line(1, "check parse, and type check a directory of .odin files."); + print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program."); + print_usage_line(1, "test build and runs procedures with the attribute @(test) in the initial package."); + print_usage_line(1, "doc generate documentation on a directory of .odin files."); + print_usage_line(1, "version print version."); + print_usage_line(1, "report print information useful to reporting a bug."); print_usage_line(0, ""); print_usage_line(0, "For further details on a command, invoke command help:"); print_usage_line(1, "e.g. `odin build -help` or `odin help build`"); @@ -1580,7 +1580,7 @@ gb_internal void remove_temp_files(lbGenerator *gen) { gb_internal void print_show_help(String const arg0, String const &command) { - print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(arg0)); + print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0)); print_usage_line(0, "Usage:"); print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command)); print_usage_line(0, ""); @@ -1590,35 +1590,35 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "One must contain the program's entry point, all must be in the same package."); print_usage_line(2, "Use `-file` to build a single file instead."); print_usage_line(2, "Examples:"); - print_usage_line(3, "odin build . # Build package in current directory"); - print_usage_line(3, "odin build # Build package in "); + print_usage_line(3, "odin build . # Build package in current directory."); + print_usage_line(3, "odin build # Build package in ."); print_usage_line(3, "odin build filename.odin -file # Build single-file package, must contain entry point."); } else if (command == "run") { print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable."); print_usage_line(2, "Append an empty flag and then the args, '-- ', to specify args for the output."); print_usage_line(2, "Examples:"); - print_usage_line(3, "odin run . # Build and run package in current directory"); - print_usage_line(3, "odin run # Build and run package in "); + print_usage_line(3, "odin run . # Build and run package in current directory."); + print_usage_line(3, "odin run # Build and run package in ."); print_usage_line(3, "odin run filename.odin -file # Build and run single-file package, must contain entry point."); } else if (command == "check") { - print_usage_line(1, "check Parse and type check directory of .odin files"); + print_usage_line(1, "check Parse and type check directory of .odin files."); print_usage_line(2, "Examples:"); - print_usage_line(3, "odin check . # Type check package in current directory"); - print_usage_line(3, "odin check # Type check package in "); + print_usage_line(3, "odin check . # Type check package in current directory."); + print_usage_line(3, "odin check # Type check package in ."); print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point."); } else if (command == "test") { - print_usage_line(1, "test Build and runs procedures with the attribute @(test) in the initial package"); + print_usage_line(1, "test Build and runs procedures with the attribute @(test) in the initial package."); } else if (command == "doc") { - print_usage_line(1, "doc generate documentation from a directory of .odin files"); + print_usage_line(1, "doc generate documentation from a directory of .odin files."); print_usage_line(2, "Examples:"); - print_usage_line(3, "odin doc . # Generate documentation on package in current directory"); - print_usage_line(3, "odin doc # Generate documentation on package in "); + print_usage_line(3, "odin doc . # Generate documentation on package in current directory."); + print_usage_line(3, "odin doc # Generate documentation on package in ."); print_usage_line(3, "odin doc filename.odin -file # Generate documentation on single-file package."); } else if (command == "version") { print_usage_line(1, "version print version"); } else if (command == "strip-semicolon") { print_usage_line(1, "strip-semicolon"); - print_usage_line(2, "Parse and type check .odin file(s) and then remove unneeded semicolons from the entire project"); + print_usage_line(2, "Parse and type check .odin file(s) and then remove unneeded semicolons from the entire project."); } bool doc = command == "doc"; @@ -1642,96 +1642,96 @@ gb_internal void print_show_help(String const arg0, String const &command) { if (doc) { print_usage_line(1, "-short"); - print_usage_line(2, "Show shortened documentation for the packages"); + print_usage_line(2, "Show shortened documentation for the packages."); print_usage_line(0, ""); print_usage_line(1, "-all-packages"); - print_usage_line(2, "Generates documentation for all packages used in the current project"); + print_usage_line(2, "Generates documentation for all packages used in the current project."); print_usage_line(0, ""); print_usage_line(1, "-doc-format"); - print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling)"); + print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling)."); print_usage_line(0, ""); } if (run_or_build) { print_usage_line(1, "-out:"); - print_usage_line(2, "Set the file name of the outputted executable"); + print_usage_line(2, "Set the file name of the outputted executable."); print_usage_line(2, "Example: -out:foo.exe"); print_usage_line(0, ""); print_usage_line(1, "-o:"); - print_usage_line(2, "Set the optimization mode for compilation"); + print_usage_line(2, "Set the optimization mode for compilation."); if (LB_USE_NEW_PASS_SYSTEM) { print_usage_line(2, "Accepted values: none, minimal, size, speed, aggressive"); } else { print_usage_line(2, "Accepted values: none, minimal, size, speed"); } print_usage_line(2, "Example: -o:speed"); - print_usage_line(2, "The default is -o:minimal"); + print_usage_line(2, "The default is -o:minimal."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-show-timings"); - print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds"); + print_usage_line(2, "Shows basic overview of the timings of different stages within the compiler in milliseconds."); print_usage_line(0, ""); print_usage_line(1, "-show-more-timings"); - print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds"); + print_usage_line(2, "Shows an advanced overview of the timings of different stages within the compiler in milliseconds."); print_usage_line(0, ""); print_usage_line(1, "-show-system-calls"); - print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler"); + print_usage_line(2, "Prints the whole command and arguments for calls to external tools like linker and assembler."); print_usage_line(0, ""); print_usage_line(1, "-export-timings:"); - print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`"); + print_usage_line(2, "Export timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`."); print_usage_line(2, "Available options:"); - print_usage_line(3, "-export-timings:json Export compile time stats to JSON"); - print_usage_line(3, "-export-timings:csv Export compile time stats to CSV"); + print_usage_line(3, "-export-timings:json Export compile time stats to JSON."); + print_usage_line(3, "-export-timings:csv Export compile time stats to CSV."); print_usage_line(0, ""); print_usage_line(1, "-export-timings-file:"); - print_usage_line(2, "Specify the filename for `-export-timings`"); + print_usage_line(2, "Specify the filename for `-export-timings`."); print_usage_line(2, "Example: -export-timings-file:timings.json"); print_usage_line(0, ""); print_usage_line(1, "-thread-count:"); - print_usage_line(2, "Override the number of threads the compiler will use to compile with"); + print_usage_line(2, "Override the number of threads the compiler will use to compile with."); print_usage_line(2, "Example: -thread-count:2"); print_usage_line(0, ""); } if (check_only) { print_usage_line(1, "-show-unused"); - print_usage_line(2, "Shows unused package declarations within the current project"); + print_usage_line(2, "Shows unused package declarations within the current project."); print_usage_line(0, ""); print_usage_line(1, "-show-unused-with-location"); - print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location"); + print_usage_line(2, "Shows unused package declarations within the current project with the declarations source location."); print_usage_line(0, ""); } if (run_or_build) { print_usage_line(1, "-keep-temp-files"); - print_usage_line(2, "Keeps the temporary files generated during compilation"); + print_usage_line(2, "Keeps the temporary files generated during compilation."); print_usage_line(0, ""); } else if (strip_semicolon) { print_usage_line(1, "-keep-temp-files"); - print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files"); + print_usage_line(2, "Keeps the temporary files generated during stripping the unneeded semicolons from files."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-collection:="); - print_usage_line(2, "Defines a library collection used for imports"); + print_usage_line(2, "Defines a library collection used for imports."); print_usage_line(2, "Example: -collection:shared=dir/to/shared"); print_usage_line(2, "Usage in Code:"); print_usage_line(3, "import \"shared:foo\""); print_usage_line(0, ""); print_usage_line(1, "-define:="); - print_usage_line(2, "Defines a scalar boolean, integer or string as global constant"); + print_usage_line(2, "Defines a scalar boolean, integer or string as global constant."); print_usage_line(2, "Example: -define:SPAM=123"); print_usage_line(2, "To use: #config(SPAM, default_value)"); print_usage_line(0, ""); @@ -1739,69 +1739,69 @@ gb_internal void print_show_help(String const arg0, String const &command) { if (build) { print_usage_line(1, "-build-mode:"); - print_usage_line(2, "Sets the build mode"); + print_usage_line(2, "Sets the build mode."); print_usage_line(2, "Available options:"); - print_usage_line(3, "-build-mode:exe Build as an executable"); - print_usage_line(3, "-build-mode:dll Build as a dynamically linked library"); - print_usage_line(3, "-build-mode:shared Build as a dynamically linked library"); - print_usage_line(3, "-build-mode:obj Build as an object file"); - print_usage_line(3, "-build-mode:object Build as an object file"); - print_usage_line(3, "-build-mode:assembly Build as an assembly file"); - print_usage_line(3, "-build-mode:assembler Build as an assembly file"); - print_usage_line(3, "-build-mode:asm Build as an assembly file"); - print_usage_line(3, "-build-mode:llvm-ir Build as an LLVM IR file"); - print_usage_line(3, "-build-mode:llvm Build as an LLVM IR file"); + print_usage_line(3, "-build-mode:exe Build as an executable."); + print_usage_line(3, "-build-mode:dll Build as a dynamically linked library."); + print_usage_line(3, "-build-mode:shared Build as a dynamically linked library."); + print_usage_line(3, "-build-mode:obj Build as an object file."); + print_usage_line(3, "-build-mode:object Build as an object file."); + print_usage_line(3, "-build-mode:assembly Build as an assembly file."); + print_usage_line(3, "-build-mode:assembler Build as an assembly file."); + print_usage_line(3, "-build-mode:asm Build as an assembly file."); + print_usage_line(3, "-build-mode:llvm-ir Build as an LLVM IR file."); + print_usage_line(3, "-build-mode:llvm Build as an LLVM IR file."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-target:"); - print_usage_line(2, "Sets the target for the executable to be built in"); + print_usage_line(2, "Sets the target for the executable to be built in."); print_usage_line(0, ""); } if (run_or_build) { print_usage_line(1, "-debug"); - print_usage_line(2, "Enabled debug information, and defines the global constant ODIN_DEBUG to be 'true'"); + print_usage_line(2, "Enabled debug information, and defines the global constant ODIN_DEBUG to be 'true'."); print_usage_line(0, ""); print_usage_line(1, "-disable-assert"); - print_usage_line(2, "Disable the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'"); + print_usage_line(2, "Disable the code generation of the built-in run-time 'assert' procedure, and defines the global constant ODIN_DISABLE_ASSERT to be 'true'."); print_usage_line(0, ""); print_usage_line(1, "-no-bounds-check"); - print_usage_line(2, "Disables bounds checking program wide"); + print_usage_line(2, "Disables bounds checking program wide."); print_usage_line(0, ""); print_usage_line(1, "-no-crt"); - print_usage_line(2, "Disables automatic linking with the C Run Time"); + print_usage_line(2, "Disables automatic linking with the C Run Time."); print_usage_line(0, ""); print_usage_line(1, "-no-thread-local"); - print_usage_line(2, "Ignore @thread_local attribute, effectively treating the program as if it is single-threaded"); + print_usage_line(2, "Ignore @thread_local attribute, effectively treating the program as if it is single-threaded."); print_usage_line(0, ""); print_usage_line(1, "-lld"); - print_usage_line(2, "Use the LLD linker rather than the default"); + print_usage_line(2, "Use the LLD linker rather than the default."); print_usage_line(0, ""); print_usage_line(1, "-use-separate-modules"); print_usage_line(1, "[EXPERIMENTAL]"); - print_usage_line(2, "The backend generates multiple build units which are then linked together"); - print_usage_line(2, "Normally, a single build unit is generated for a standard project"); + print_usage_line(2, "The backend generates multiple build units which are then linked together."); + print_usage_line(2, "Normally, a single build unit is generated for a standard project."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-no-threaded-checker"); - print_usage_line(2, "Disabled multithreading in the semantic checker stage"); + print_usage_line(2, "Disabled multithreading in the semantic checker stage."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-vet"); - print_usage_line(2, "Do extra checks on the code"); + print_usage_line(2, "Do extra checks on the code."); print_usage_line(2, "Extra checks include:"); print_usage_line(2, "-vet-unused"); print_usage_line(2, "-vet-shadowing"); @@ -1809,70 +1809,70 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-vet-unused"); - print_usage_line(2, "Checks for unused declarations"); + print_usage_line(2, "Checks for unused declarations."); print_usage_line(0, ""); print_usage_line(1, "-vet-shadowing"); - print_usage_line(2, "Checks for variable shadowing within procedures"); + print_usage_line(2, "Checks for variable shadowing within procedures."); print_usage_line(0, ""); print_usage_line(1, "-vet-using-stmt"); - print_usage_line(2, "Checks for the use of 'using' as a statement"); - print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring"); + print_usage_line(2, "Checks for the use of 'using' as a statement."); + print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring."); print_usage_line(0, ""); print_usage_line(1, "-vet-using-param"); - print_usage_line(2, "Checks for the use of 'using' on procedure parameters"); - print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring"); + print_usage_line(2, "Checks for the use of 'using' on procedure parameters."); + print_usage_line(2, "'using' is considered bad practice outside of immediate refactoring."); print_usage_line(0, ""); print_usage_line(1, "-vet-style"); - print_usage_line(2, "Errs on missing trailing commas followed by a newline"); - print_usage_line(2, "Errs on deprecated syntax"); - print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style)"); + print_usage_line(2, "Errs on missing trailing commas followed by a newline."); + print_usage_line(2, "Errs on deprecated syntax."); + print_usage_line(2, "Does not err on unneeded tokens (unlike -strict-style)."); print_usage_line(0, ""); print_usage_line(1, "-vet-semicolon"); - print_usage_line(2, "Errs on unneeded semicolons"); + print_usage_line(2, "Errs on unneeded semicolons."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-ignore-unknown-attributes"); - print_usage_line(2, "Ignores unknown attributes"); - print_usage_line(2, "This can be used with metaprogramming tools"); + print_usage_line(2, "Ignores unknown attributes."); + print_usage_line(2, "This can be used with metaprogramming tools."); print_usage_line(0, ""); if (command != "test") { print_usage_line(1, "-no-entry-point"); - print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure)"); + print_usage_line(2, "Removes default requirement of an entry point (e.g. main procedure)."); print_usage_line(0, ""); } } if (test_only) { print_usage_line(1, "-test-name:"); - print_usage_line(2, "Run specific test only by name"); + print_usage_line(2, "Run specific test only by name."); print_usage_line(0, ""); } if (run_or_build) { print_usage_line(1, "-minimum-os-version:"); - print_usage_line(2, "Sets the minimum OS version targeted by the application"); + print_usage_line(2, "Sets the minimum OS version targeted by the application."); print_usage_line(2, "e.g. -minimum-os-version:12.0.0"); - print_usage_line(2, "(Only used when target is Darwin)"); + print_usage_line(2, "(Only used when target is Darwin.)"); print_usage_line(0, ""); print_usage_line(1, "-extra-linker-flags:"); - print_usage_line(2, "Adds extra linker specific flags in a string"); + print_usage_line(2, "Adds extra linker specific flags in a string."); print_usage_line(0, ""); print_usage_line(1, "-extra-assembler-flags:"); - print_usage_line(2, "Adds extra assembler specific flags in a string"); + print_usage_line(2, "Adds extra assembler specific flags in a string."); print_usage_line(0, ""); print_usage_line(1, "-microarch:"); - print_usage_line(2, "Specifies the specific micro-architecture for the build in a string"); + print_usage_line(2, "Specifies the specific micro-architecture for the build in a string."); print_usage_line(2, "Examples:"); print_usage_line(3, "-microarch:sandybridge"); print_usage_line(3, "-microarch:native"); @@ -1880,7 +1880,7 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-reloc-mode:"); - print_usage_line(2, "Specifies the reloc mode"); + print_usage_line(2, "Specifies the reloc mode."); print_usage_line(2, "Options:"); print_usage_line(3, "default"); print_usage_line(3, "static"); @@ -1889,65 +1889,65 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-disable-red-zone"); - print_usage_line(2, "Disable red zone on a supported freestanding target"); + print_usage_line(2, "Disable red zone on a supported freestanding target."); print_usage_line(0, ""); print_usage_line(1, "-dynamic-map-calls"); - print_usage_line(2, "Use dynamic map calls to minimize code generation at the cost of runtime execution"); + print_usage_line(2, "Use dynamic map calls to minimize code generation at the cost of runtime execution."); print_usage_line(0, ""); } if (check) { print_usage_line(1, "-disallow-do"); - print_usage_line(2, "Disallows the 'do' keyword in the project"); + print_usage_line(2, "Disallows the 'do' keyword in the project."); print_usage_line(0, ""); print_usage_line(1, "-default-to-nil-allocator"); - print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing"); + print_usage_line(2, "Sets the default allocator to be the nil_allocator, an allocator which does nothing."); print_usage_line(0, ""); print_usage_line(1, "-strict-style"); - print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons"); - print_usage_line(2, "Errs on missing trailing commas followed by a newline"); - print_usage_line(2, "Errs on deprecated syntax"); + print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons."); + print_usage_line(2, "Errs on missing trailing commas followed by a newline."); + print_usage_line(2, "Errs on deprecated syntax."); print_usage_line(0, ""); print_usage_line(1, "-ignore-warnings"); - print_usage_line(2, "Ignores warning messages"); + print_usage_line(2, "Ignores warning messages."); print_usage_line(0, ""); print_usage_line(1, "-warnings-as-errors"); - print_usage_line(2, "Treats warning messages as error messages"); + print_usage_line(2, "Treats warning messages as error messages."); print_usage_line(0, ""); print_usage_line(1, "-terse-errors"); - print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line"); + print_usage_line(2, "Prints a terse error message without showing the code on that line and the location in that line."); print_usage_line(0, ""); print_usage_line(1, "-error-pos-style:"); - print_usage_line(2, "Options are 'unix', 'odin' and 'default' (odin)"); + print_usage_line(2, "Options are 'unix', 'odin' and 'default' (odin)."); print_usage_line(2, "'odin' file/path(45:3)"); print_usage_line(2, "'unix' file/path:45:3:"); print_usage_line(0, ""); print_usage_line(1, "-max-error-count:"); - print_usage_line(2, "Set the maximum number of errors that can be displayed before the compiler terminates"); - print_usage_line(2, "Must be an integer >0"); - print_usage_line(2, "If not set, the default max error count is %d", DEFAULT_MAX_ERROR_COLLECTOR_COUNT); + print_usage_line(2, "Set the maximum number of errors that can be displayed before the compiler terminates."); + print_usage_line(2, "Must be an integer >0."); + print_usage_line(2, "If not set, the default max error count is %d.", DEFAULT_MAX_ERROR_COLLECTOR_COUNT); print_usage_line(0, ""); print_usage_line(1, "-foreign-error-procedures"); - print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit"); + print_usage_line(2, "States that the error procedures used in the runtime are defined in a separate translation unit."); print_usage_line(0, ""); } if (run_or_build) { print_usage_line(1, "-sanitize:"); - print_usage_line(2, "Enables sanitization analysis"); - print_usage_line(2, "Options are 'address', 'memory', and 'thread'"); - print_usage_line(2, "NOTE: This flag can be used multiple times"); + print_usage_line(2, "Enables sanitization analysis."); + print_usage_line(2, "Options are 'address', 'memory', and 'thread'."); + print_usage_line(2, "NOTE: This flag can be used multiple times."); print_usage_line(0, ""); } @@ -1956,24 +1956,24 @@ gb_internal void print_show_help(String const arg0, String const &command) { #if defined(GB_SYSTEM_WINDOWS) print_usage_line(1, "-ignore-vs-search"); print_usage_line(2, "[Windows only]"); - print_usage_line(2, "Ignores the Visual Studio search for library paths"); + print_usage_line(2, "Ignores the Visual Studio search for library paths."); print_usage_line(0, ""); print_usage_line(1, "-resource:"); print_usage_line(2, "[Windows only]"); - print_usage_line(2, "Defines the resource file for the executable"); + print_usage_line(2, "Defines the resource file for the executable."); print_usage_line(2, "Example: -resource:path/to/file.rc"); print_usage_line(0, ""); print_usage_line(1, "-pdb-name:"); print_usage_line(2, "[Windows only]"); - print_usage_line(2, "Defines the generated PDB name when -debug is enabled"); + print_usage_line(2, "Defines the generated PDB name when -debug is enabled."); print_usage_line(2, "Example: -pdb-name:different.pdb"); print_usage_line(0, ""); print_usage_line(1, "-subsystem: