From 16c176dc89ee4557a3e86803434de6d5f07d55f4 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Mon, 23 Oct 2023 22:03:06 +0200 Subject: Implement new union intrinsics and add support for len/cap --- src/check_builtin.cpp | 139 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 49095a7a8..8fae04b6e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1780,7 +1780,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As mode = Addressing_Constant; value = exact_value_i64(bt->SimdVector.count); type = t_untyped_integer; - } + } else if (is_type_union(op_type)) { + Type *u = base_type(op_type); + mode = Addressing_Constant; + value = exact_value_i64(u->Union.variants.count); + type = t_untyped_integer; + } if (operand->mode == Addressing_Type && mode != Addressing_Constant) { mode = Addressing_Invalid; } @@ -5117,6 +5122,138 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; + case BuiltinProc_type_union_tag: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Type; + operand->type = union_tag_type(u); + } + break; + + case BuiltinProc_type_union_tag_offset: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + // NOTE(jakubtomsu): forces calculation of variant_block_size + type_size_of(u); + i64 tag_offset = u->Union.variant_block_size; + GB_ASSERT(tag_offset > 0); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(tag_offset); + } + break; + + case BuiltinProc_type_variant_type: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + Operand x = {}; + check_expr_or_type(c, &x, ce->args[1]); + if (!is_type_integer(x.type) || x.mode != Addressing_Constant) { + error(call, "Expected a constant integer for '%.*s", LIT(builtin_name)); + operand->mode = Addressing_Type; + operand->type = t_invalid; + return false; + } + + i64 index = big_int_to_i64(&x.value.value_integer); + if (u->Union.kind != UnionType_no_nil) { + index -= 1; + } + + if (index < 0 || index >= u->Union.variants.count) { + error(call, "Variant tag out of bounds index for '%.*s", LIT(builtin_name)); + operand->mode = Addressing_Type; + operand->type = t_invalid; + return false; + } + + operand->mode = Addressing_Type; + operand->type = u->Union.variants[index]; + } + break; + + case BuiltinProc_type_variant_tag: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *v = check_type(c, ce->args[1]); + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(union_variant_index(u, v)); + } + break; + case BuiltinProc_type_struct_field_count: operand->value = exact_value_i64(0); if (operand->mode != Addressing_Type) { -- cgit v1.2.3 From f7e05162547c9444261a215992ea3c39f22a90b6 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Wed, 25 Oct 2023 15:47:18 +0200 Subject: Fix the intrinsics, add min and max --- src/check_builtin.cpp | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8fae04b6e..a26ac4baa 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2597,7 +2597,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { + if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2662,6 +2662,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.min_value; return true; + } else if (is_type_union(type)) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Union); + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + i64 min_tag = bt->Union.kind == UnionType_no_nil ? 0 : 1; + operand->value = exact_value_i64(min_tag); + return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'min', got %s", type_str); @@ -2766,7 +2774,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { + if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2836,6 +2844,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.max_value; return true; + } else if (is_type_union(type)) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Union); + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + i64 max_tag = (bt->Union.kind == UnionType_no_nil ? 0 : 1) + bt->Union.variants.count - 1; + operand->value = exact_value_i64(max_tag); + return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'max', got %s", type_str); @@ -5180,7 +5196,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; - case BuiltinProc_type_variant_type: + case BuiltinProc_type_variant_type_of: { if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); @@ -5210,10 +5226,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } i64 index = big_int_to_i64(&x.value.value_integer); - if (u->Union.kind != UnionType_no_nil) { - index -= 1; - } - if (index < 0 || index >= u->Union.variants.count) { error(call, "Variant tag out of bounds index for '%.*s", LIT(builtin_name)); operand->mode = Addressing_Type; @@ -5226,7 +5238,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; - case BuiltinProc_type_variant_tag: + case BuiltinProc_type_variant_index_of: { if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); @@ -5247,10 +5259,26 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *v = check_type(c, ce->args[1]); u = base_type(u); GB_ASSERT(u->kind == Type_Union); + + i64 index = -1; + for_array(i, u->Union.variants) { + Type *vt = u->Union.variants[i]; + if (union_variant_index_types_equal(v, vt)) { + index = i64(i); + break; + } + } + + if (index < 0) { + error(operand->expr, "Expected a variant type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } operand->mode = Addressing_Constant; operand->type = t_untyped_integer; - operand->value = exact_value_i64(union_variant_index(u, v)); + operand->value = exact_value_i64(index); } break; -- cgit v1.2.3 From 2f8d60ec47b32206172839c2d96b66cb872985be Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Wed, 25 Oct 2023 17:33:27 +0200 Subject: Fix indentation --- src/check_builtin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index a26ac4baa..7cadf49a0 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1781,11 +1781,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As value = exact_value_i64(bt->SimdVector.count); type = t_untyped_integer; } else if (is_type_union(op_type)) { - Type *u = base_type(op_type); + Type *u = base_type(op_type); mode = Addressing_Constant; value = exact_value_i64(u->Union.variants.count); type = t_untyped_integer; - } + } if (operand->mode == Addressing_Type && mode != Addressing_Constant) { mode = Addressing_Invalid; } -- cgit v1.2.3 From 625cb032841c86d046d0ceb8123936bd393785ea Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Wed, 25 Oct 2023 20:23:24 +0200 Subject: Rename type_union_tag to type_union_tag_type --- core/intrinsics/intrinsics.odin | 4 +- src/check_builtin.cpp | 2 +- src/checker_builtin_procs.hpp | 4 +- test.odin | 272 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 277 insertions(+), 5 deletions(-) create mode 100644 test.odin (limited to 'src/check_builtin.cpp') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 505309a8e..62f3d1ad2 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -164,9 +164,9 @@ type_has_nil :: proc($T: typeid) -> bool --- type_is_specialization_of :: proc($T, $S: typeid) -> bool --- type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- -type_union_tag :: proc($U: typeid) -> typeid where type_is_union(U) --- +type_union_tag_type :: proc($U: typeid) -> typeid where type_is_union(U) --- type_union_tag_offset :: proc($U: typeid) -> int where type_is_union(U) --- -type_variant_type_of_of :: proc($U: typeid, $index: int) -> typeid where type_is_union(U) --- +type_variant_type_of :: proc($U: typeid, $index: int) -> typeid where type_is_union(U) --- type_variant_index_of :: proc($U, $V: typeid) -> int where type_is_union(U) --- type_has_field :: proc($T: typeid, $name: string) -> bool --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 7cadf49a0..5907b30e3 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5138,7 +5138,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; - case BuiltinProc_type_union_tag: + case BuiltinProc_type_union_tag_type: { if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 8053d54f2..35ca9c51e 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -260,7 +260,7 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_is_specialization_of, BuiltinProc_type_is_variant_of, - BuiltinProc_type_union_tag, + BuiltinProc_type_union_tag_type, BuiltinProc_type_union_tag_offset, BuiltinProc_type_variant_type_of, BuiltinProc_type_variant_index_of, @@ -562,7 +562,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_union_tag"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_tag_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/test.odin b/test.odin new file mode 100644 index 000000000..0930184ac --- /dev/null +++ b/test.odin @@ -0,0 +1,272 @@ +package test + +import "core:fmt" +import "core:intrinsics" +import "core:mem" +import "core:reflect" +import "core:runtime" +import "core:slice" + +// TODO: extend for loops? + +get_tag :: proc(u: $T) -> int where intrinsics.type_is_union(T) { + u := u + return int( + (cast(^intrinsics.type_union_tag_type(T))(uintptr(&u) + + intrinsics.type_union_tag_offset(T)))^, + ) +} + +set_tag :: proc(u: ^$T, tag: int) where intrinsics.type_is_union(T) { + TAG :: intrinsics.type_union_tag_type(T) + (cast(^TAG)(uintptr(u) + intrinsics.type_union_tag_offset(T)))^ = TAG(tag) +} + +get_variant_index :: proc(u: $T) -> int where intrinsics.type_is_union(T) { + return min(T) + get_tag(u) +} + +main :: proc() { + Foo :: union { + f32, // 1 + u16, // 2 + u8, // 3 + } + + fmt.println(typeid_of(Foo)) + fmt.println("size_of:", size_of(Foo)) + fmt.println("len:", len(Foo)) + fmt.println("cap:", cap(Foo)) + fmt.println("min:", min(Foo)) + fmt.println("max:", max(Foo)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Foo))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Foo)) + fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Foo, 0))) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Foo, 1))) + fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Foo, 2))) + fmt.println("index of f32:", intrinsics.type_variant_index_of(Foo, f32)) + fmt.println("index of u16:", intrinsics.type_variant_index_of(Foo, u16)) + fmt.println("index of u8 :", intrinsics.type_variant_index_of(Foo, u8)) + // Goofy test of unsafe tag manipulation + foo: Foo = u16(255 + 255 << 8) + assert(get_tag(foo) == 2) + fmt.println(foo) + set_tag(&foo, 3) + assert(get_tag(foo) == 3) + fmt.println(foo) + fmt.println() + + Bar :: union #no_nil { + i8, // 0 + u8, // 1 + b8, // 2 + } + + fmt.println(typeid_of(Bar)) + fmt.println("size_of:", size_of(Bar)) + fmt.println("len:", len(Bar)) + fmt.println("cap:", cap(Bar)) + fmt.println("min:", min(Bar)) + fmt.println("max:", max(Bar)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Bar))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Bar)) + fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Bar, 0))) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Bar, 1))) + fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Bar, 2))) + fmt.println("index of f32:", intrinsics.type_variant_index_of(Bar, i8)) + fmt.println("index of u16:", intrinsics.type_variant_index_of(Bar, u8)) + fmt.println("index of u8: ", intrinsics.type_variant_index_of(Bar, b8)) + fmt.println() + + Baz :: union #shared_nil { + []u8, // 1 + rawptr, // 2 + ^u8, // 3 + } + + fmt.println(typeid_of(Baz)) + fmt.println("size_of:", size_of(Baz)) + fmt.println("len:", len(Baz)) + fmt.println("cap:", cap(Baz)) + fmt.println("min:", min(Baz)) + fmt.println("max:", max(Baz)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Baz))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Baz)) + fmt.println("type of 0:", typeid_of(intrinsics.type_variant_type_of(Baz, 0))) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Baz, 1))) + fmt.println("type of 2:", typeid_of(intrinsics.type_variant_type_of(Baz, 2))) + fmt.println("index of []u8: ", intrinsics.type_variant_index_of(Baz, []u8)) + fmt.println("index of rawptr:", intrinsics.type_variant_index_of(Baz, rawptr)) + fmt.println("index of ^u8: ", intrinsics.type_variant_index_of(Baz, ^u8)) + fmt.println() + + Mby :: Maybe(f32) + + fmt.println(typeid_of(Mby)) + fmt.println("size_of:", size_of(Mby)) + fmt.println("len:", len(Mby)) + fmt.println("cap:", cap(Mby)) + fmt.println("min:", min(Mby)) + fmt.println("max:", max(Mby)) + fmt.println("tag:", typeid_of(intrinsics.type_union_tag_type(Mby))) + fmt.println("tag offset:", intrinsics.type_union_tag_offset(Mby)) + fmt.println("type of 1:", typeid_of(intrinsics.type_variant_type_of(Mby, 0))) + fmt.println("index of f32:", intrinsics.type_variant_index_of(Mby, f32)) + fmt.println() + + // #unroll for i in 0 ..< intrinsics.type_proc_parameter_count(Proc) { + // fmt.println(intrinsics.type_proc_parameter_type(Proc, i)) + // } + + // arr: Packed_Union_Array(Foo) + // init(&arr) + + // append(&arr, f32(1.23)) + // append(&arr, f32(-1)) + // append(&arr, f32(-2)) + // append(&arr, f32(-3)) + // append(&arr, u8(0)) + // append(&arr, u8(255)) + // append(&arr, u8(255)) + + // fmt.println(get_data(arr, f32)) + // fmt.println(get_data(arr, u16)) + // fmt.println(get_data(arr, u8)) + + // pool: Packed_Union_Pool(Foo) + // packed_union_pool_init(&pool) + + // a := packed_union_pool_insert(&pool, f32(1.0)) + // packed_union_pool_insert(&pool, f32(3.0)) + // packed_union_pool_insert(&pool, u8(0)) + // packed_union_pool_remove(&pool, a) + // packed_union_pool_insert(&pool, f32(1.234)) + + // // prints 1.234 since it was overwritten + // fmt.println(a^) +} + + +// Packed_Union_Array_Variant :: struct { +// data: []u8, +// len: int, +// } + +// Packed_Union_Array :: struct($T: typeid) where intrinsics.type_is_union(T) { +// variants: [len(T)]Packed_Union_Array_Variant, +// allocator: runtime.Allocator, +// } + +// packed_union_array_init :: proc( +// a: ^$T/Packed_Union_Array($U), +// cap: int = 32, +// allocator := context.allocator, +// ) { +// a^ = { +// allocator = allocator, +// } + +// // RTTI hack since a loop cannot produce compile-time constant +// ti := reflect.type_info_base(type_info_of(U)).variant.(reflect.Type_Info_Union) +// for &v, i in a.variants { +// data, _ := mem.alloc_bytes_non_zeroed(cap * ti.variants[i].size) +// v = { +// data = data, +// len = 0, +// } +// } +// } + +// packed_union_array_append :: proc( +// a: ^$T/Packed_Union_Array($U), +// value: $V, +// ) where intrinsics.type_is_variant_of(U, V) { +// variants := &a.variants[intrinsics.type_variant_index_of(U, V)] + +// if variants.len >= len(variants.data) { +// // alloc more +// } + +// data := packed_union_array_get_data_buf(a^, V) +// data[variants.len / size_of(V)] = value +// variants.len += size_of(V) +// } + +// packed_union_array_set :: proc( +// a: $T/Packed_Union_Array($U), +// index: int, +// value: $V, +// ) where intrinsics.type_is_variant_of(U, V) { +// packed_union_array_get_data(a, V)[index] = value +// } + +// packed_union_array_get :: proc( +// a: $T/Packed_Union_Array($U), +// $V: typeid, +// index: int, +// ) -> V where intrinsics.type_is_variant_of(U, V) { +// return packed_union_array_get_data(a, V)[index] +// } + +// packed_union_array_get_data :: proc( +// a: $T/Packed_Union_Array($U), +// $V: typeid, +// ) -> []V where intrinsics.type_is_variant_of(U, V) { +// vars := a.variants[intrinsics.type_variant_index_of(U, V)] +// return slice.reinterpret([]V, vars.data)[:vars.len / size_of(V)] +// } + +// packed_union_array_get_data_buf :: proc( +// a: $T/Packed_Union_Array($U), +// $V: typeid, +// ) -> []V where intrinsics.type_is_variant_of(U, V) { +// return slice.reinterpret([]V, a.variants[intrinsics.type_variant_index_of(U, V)].data) +// } + +// // Basically like a pool with free list size buckets, but optimized for the specific union type. +// Packed_Union_Pool :: struct($T: typeid) where intrinsics.type_is_union(T) { +// // Should be a fast allocator like an arena. +// allocator: runtime.Allocator, +// free_lists: [len(T)]rawptr, +// } + +// Packed_Union_Pool_Item :: struct($T: typeid) { +// data: T, +// next_free: rawptr, +// } + +// packed_union_pool_init :: proc(p: ^$T/Packed_Union_Pool($U), allocator := context.allocator) { +// p^ = { +// allocator = allocator, +// } +// } + +// packed_union_pool_insert :: proc( +// p: ^$T/Packed_Union_Pool($U), +// val: $V, +// ) -> ( +// result: ^V, +// err: mem.Allocator_Error, +// ) #optional_allocator_error { +// ptr := cast(^Packed_Union_Pool_Item(V))p.free_lists[intrinsics.type_variant_index_of(U, V)] +// if ptr == nil { +// ptr = new(Packed_Union_Pool_Item(V), p.allocator) or_return +// } else { +// p.free_lists[intrinsics.type_variant_index_of(U, V)] = ptr.next_free +// } + +// ptr^ = { +// data = val, +// next_free = nil, +// } + +// return &ptr.data, nil +// } + +// packed_union_pool_remove :: proc(p: ^$T/Packed_Union_Pool($U), ptr: ^$V) { +// assert(ptr != nil) + +// item := cast(^Packed_Union_Pool_Item(V))ptr +// item.next_free = p.free_lists[intrinsics.type_variant_index_of(U, V)] +// p.free_lists[intrinsics.type_variant_index_of(U, V)] = item +// } -- cgit v1.2.3 From 160b23f991ff796b1d9a95ab793eabad9a2c33c6 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Fri, 27 Oct 2023 11:23:26 +0200 Subject: Remove len,cap,min,max and implement type_union_base_tag_value, type_union_variant_count --- core/intrinsics/intrinsics.odin | 8 +++-- src/check_builtin.cpp | 79 ++++++++++++++++++++++++++++------------- src/checker_builtin_procs.hpp | 14 +++++--- 3 files changed, 69 insertions(+), 32 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 62f3d1ad2..afa0efa36 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -164,9 +164,11 @@ type_has_nil :: proc($T: typeid) -> bool --- type_is_specialization_of :: proc($T, $S: typeid) -> bool --- type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- -type_union_tag_type :: proc($U: typeid) -> typeid where type_is_union(U) --- -type_union_tag_offset :: proc($U: typeid) -> int where type_is_union(U) --- -type_variant_type_of :: proc($U: typeid, $index: int) -> typeid where type_is_union(U) --- +type_union_tag_type :: proc($T: typeid) -> typeid where type_is_union(T) --- +type_union_tag_offset :: proc($T: typeid) -> int where type_is_union(T) --- +type_union_base_tag_value :: proc($T: typeid) -> int where type_is_union(U) --- +type_union_variant_count :: proc($T: typeid) -> int where type_is_union(T) --- +type_variant_type_of :: proc($T: typeid, $index: int) -> typeid where type_is_union(T) --- type_variant_index_of :: proc($U, $V: typeid) -> int where type_is_union(U) --- type_has_field :: proc($T: typeid, $name: string) -> bool --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 5907b30e3..03850ce50 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1780,11 +1780,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As mode = Addressing_Constant; value = exact_value_i64(bt->SimdVector.count); type = t_untyped_integer; - } else if (is_type_union(op_type)) { - Type *u = base_type(op_type); - mode = Addressing_Constant; - value = exact_value_i64(u->Union.variants.count); - type = t_untyped_integer; } if (operand->mode == Addressing_Type && mode != Addressing_Constant) { mode = Addressing_Invalid; @@ -2597,7 +2592,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { + if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2662,14 +2657,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.min_value; return true; - } else if (is_type_union(type)) { - Type *bt = base_type(type); - GB_ASSERT(bt->kind == Type_Union); - operand->mode = Addressing_Constant; - operand->type = t_untyped_integer; - i64 min_tag = bt->Union.kind == UnionType_no_nil ? 0 : 1; - operand->value = exact_value_i64(min_tag); - return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'min', got %s", type_str); @@ -2774,7 +2761,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *original_type = operand->type; Type *type = base_type(operand->type); - if (operand->mode == Addressing_Type && (is_type_enumerated_array(type) || is_type_union(type))) { + if (operand->mode == Addressing_Type && is_type_enumerated_array(type)) { // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); @@ -2844,14 +2831,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = bt->EnumeratedArray.index; operand->value = *bt->EnumeratedArray.max_value; return true; - } else if (is_type_union(type)) { - Type *bt = base_type(type); - GB_ASSERT(bt->kind == Type_Union); - operand->mode = Addressing_Constant; - operand->type = t_untyped_integer; - i64 max_tag = (bt->Union.kind == UnionType_no_nil ? 0 : 1) + bt->Union.variants.count - 1; - operand->value = exact_value_i64(max_tag); - return true; } gbString type_str = type_to_string(original_type); error(call, "Invalid type for 'max', got %s", type_str); @@ -5163,7 +5142,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = union_tag_type(u); } break; - + case BuiltinProc_type_union_tag_offset: { if (operand->mode != Addressing_Type) { @@ -5196,6 +5175,58 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; + case BuiltinProc_type_union_base_tag_value: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(u->Union.kind == UnionType_no_nil ? 0 : 1); + } break; + + case BuiltinProc_type_union_variant_count: + { + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + Type *u = operand->type; + + if (!is_type_union(u)) { + error(operand->expr, "Expected a union type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + u = base_type(u); + GB_ASSERT(u->kind == Type_Union); + + operand->mode = Addressing_Constant; + operand->type = t_untyped_integer; + operand->value = exact_value_i64(u->Union.variants.count); + } break; + case BuiltinProc_type_variant_type_of: { if (operand->mode != Addressing_Type) { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 35ca9c51e..3bab16293 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -262,6 +262,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_is_variant_of, BuiltinProc_type_union_tag_type, BuiltinProc_type_union_tag_offset, + BuiltinProc_type_union_base_tag_value, + BuiltinProc_type_union_variant_count, BuiltinProc_type_variant_type_of, BuiltinProc_type_variant_index_of, @@ -561,11 +563,13 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_specialization_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_union_tag_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_variant_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_tag_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_tag_offset"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_base_tag_value"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_union_variant_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_type_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_variant_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From f809788f75f997ceebbbbfa0aa138f2ae2011e1e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 23 Nov 2023 17:31:00 +0000 Subject: Add missing type information for soa structs --- src/check_builtin.cpp | 2 ++ src/checker.cpp | 5 +++++ src/llvm_backend_expr.cpp | 6 ++++++ src/llvm_backend_type.cpp | 7 ++++++- 4 files changed, 19 insertions(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index ce628bc1d..c0061a397 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2088,6 +2088,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As t = default_type(t); add_type_info_type(c, t); + GB_ASSERT(t_type_info_ptr != nullptr); + add_type_info_type(c, t_type_info_ptr); if (is_operand_value(o) && is_type_typeid(t)) { add_package_dependency(c, "runtime", "__type_info_of"); diff --git a/src/checker.cpp b/src/checker.cpp index 0366cf05d..6dae99027 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2211,9 +2211,14 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { Entity *e = entry.value; switch (bt->Struct.soa_kind) { case StructSoa_Dynamic: + add_min_dep_type_info(c, t_type_info_ptr); // append_soa + add_min_dep_type_info(c, t_allocator); /*fallthrough*/ case StructSoa_Slice: + add_min_dep_type_info(c, t_int); + add_min_dep_type_info(c, t_uint); + /*fallthrough*/ case StructSoa_Fixed: add_min_dep_type_info(c, alloc_type_pointer(e->type)); break; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 8678a125c..d1176f896 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2939,6 +2939,12 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { } else if (is_type_soa_pointer(tv.type)) { ast_node(ie, IndexExpr, ue_expr); lbValue addr = lb_build_addr_ptr(p, ie->expr); + + if (is_type_pointer(type_deref(addr.type))) { + addr = lb_emit_load(p, addr); + } + GB_ASSERT(is_type_pointer(addr.type)); + lbValue index = lb_build_expr(p, ie->index); if (!build_context.no_bounds_check) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 02dad2a3a..e291e40a5 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -9,7 +9,12 @@ gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_ } } if (err_on_not_found) { - GB_PANIC("NOT FOUND lb_type_info_index %s @ index %td", type_to_string(type), index); + gb_printf_err("NOT FOUND lb_type_info_index:\n\t%s\n\t@ index %td\n\tmax count: %u\nFound:\n", type_to_string(type), index, set->count); + for (auto const &entry : *set) { + isize type_info_index = entry.key; + gb_printf_err("\t%s\n", type_to_string(info->type_info_types[type_info_index])); + } + GB_PANIC("NOT FOUND"); } return -1; } -- cgit v1.2.3 From 64ed4389ffed678c1fea3a3522af7425357f79dc Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 27 Dec 2023 15:00:33 +0100 Subject: fix load directive with absolute paths --- src/check_builtin.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c0061a397..b3aaab754 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1083,13 +1083,16 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String ast_node(bd, BasicDirective, ce->proc); String builtin_name = bd->name.string; - String base_dir = dir_from_path(get_file_path_string(call->file_id)); - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); + String path; + if (gb_path_is_absolute((char*)original_string.text)) { + path = original_string; + } else { + String base_dir = dir_from_path(get_file_path_string(call->file_id)); + BlockingMutex *ignore_mutex = nullptr; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + } MUTEX_GUARD(&c->info->load_file_mutex); -- cgit v1.2.3 From 0b83e3dae5c96550f1500612aa7073ee8f6ae5b6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Jan 2024 14:29:14 +0000 Subject: Enforce naming the parameters with `builtin.quaternion` to reduce confusion --- core/encoding/json/unmarshal.odin | 6 +- core/math/linalg/general.odin | 2 +- core/runtime/internal.odin | 12 ++-- core/sys/windows/advapi32.odin | 5 ++ examples/demo/demo.odin | 8 ++- src/check_builtin.cpp | 139 ++++++++++++++++++++++++++++++++++---- src/llvm_backend_proc.cpp | 43 ++++++++---- 7 files changed, 174 insertions(+), 41 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index afcc43c0c..c1905f6b0 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -137,9 +137,9 @@ assign_float :: proc(val: any, f: $T) -> bool { case complex64: dst = complex(f32(f), 0) case complex128: dst = complex(f64(f), 0) - case quaternion64: dst = quaternion(f16(f), 0, 0, 0) - case quaternion128: dst = quaternion(f32(f), 0, 0, 0) - case quaternion256: dst = quaternion(f64(f), 0, 0, 0) + case quaternion64: dst = quaternion(w=f16(f), x=0, y=0, z=0) + case quaternion128: dst = quaternion(w=f32(f), x=0, y=0, z=0) + case quaternion256: dst = quaternion(w=f64(f), x=0, y=0, z=0) case: return false } diff --git a/core/math/linalg/general.odin b/core/math/linalg/general.odin index b58305c63..a61fe9189 100644 --- a/core/math/linalg/general.odin +++ b/core/math/linalg/general.odin @@ -70,7 +70,7 @@ outer_product :: builtin.outer_product @(require_results) quaternion_inverse :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) { - return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0) + return conj(q) * quaternion(w=1.0/dot(q, q), x=0, y=0, z=0) } diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index d0e550743..0d7bdee8b 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -730,7 +730,7 @@ mul_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 { t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1 t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { @@ -742,7 +742,7 @@ mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1 t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { @@ -754,7 +754,7 @@ mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1 t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 { @@ -768,7 +768,7 @@ quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 { t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2 t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { @@ -782,7 +782,7 @@ quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 { t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2 t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { @@ -796,7 +796,7 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 { t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2 t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2 - return quaternion(t0, t1, t2, t3) + return quaternion(w=t0, x=t1, y=t2, z=t3) } @(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) diff --git a/core/sys/windows/advapi32.odin b/core/sys/windows/advapi32.odin index dc7ec1e08..86e173211 100644 --- a/core/sys/windows/advapi32.odin +++ b/core/sys/windows/advapi32.odin @@ -13,6 +13,11 @@ foreign advapi32 { DesiredAccess: DWORD, TokenHandle: ^HANDLE) -> BOOL --- + OpenThreadToken :: proc(ThreadHandle: HANDLE, + DesiredAccess: DWORD, + OpenAsSelf: BOOL, + TokenHandle: ^HANDLE) -> BOOL --- + CryptAcquireContextW :: proc(hProv: ^HCRYPTPROV, szContainer, szProvider: wstring, dwProvType, dwFlags: DWORD) -> DWORD --- CryptGenRandom :: proc(hProv: HCRYPTPROV, dwLen: DWORD, buf: LPVOID) -> DWORD --- CryptReleaseContext :: proc(hProv: HCRYPTPROV, dwFlags: DWORD) -> DWORD --- diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index b890d5778..bc6a4d9ea 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1514,7 +1514,7 @@ quaternions :: proc() { { // Quaternion operations q := 1 + 2i + 3j + 4k - r := quaternion(5, 6, 7, 8) + r := quaternion(real=5, imag=6, jmag=7, kmag=8) t := q * r fmt.printf("(%v) * (%v) = %v\n", q, r, t) v := q / r @@ -1527,8 +1527,10 @@ quaternions :: proc() { { // The quaternion types q128: quaternion128 // 4xf32 q256: quaternion256 // 4xf64 - q128 = quaternion(1, 0, 0, 0) - q256 = 1 // quaternion(1, 0, 0, 0) + q128 = quaternion(w=1, x=0, y=0, z=0) + q256 = 1 // quaternion(x=0, y=0, z=0, w=1) + + // NOTE: The internal memory layout of a quaternion is xyzw } { // Built-in procedures q := 1 + 2i + 3j + 4k diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b3aaab754..55962f89f 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1666,7 +1666,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (ce->args.count > 0) { if (ce->args[0]->kind == Ast_FieldValue) { - if (id != BuiltinProc_soa_zip) { + switch (id) { + case BuiltinProc_soa_zip: + case BuiltinProc_quaternion: + // okay + break; + default: error(call, "'field = value' calling is not allowed on built-in procedures"); return false; } @@ -2299,8 +2304,32 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } case BuiltinProc_quaternion: { + bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue); + + bool fail = false; + for (Ast *arg : ce->args) { + bool mix = false; + if (first_is_field_value) { + mix = arg->kind != Ast_FieldValue; + } else { + mix = arg->kind == Ast_FieldValue; + } + if (mix) { + error(arg, "Mixture of 'field = value' and value elements in the procedure call '%.*s' is not allowed", LIT(builtin_name)); + fail = true; + break; + } + } + + if (fail) { + operand->type = t_untyped_quaternion; + operand->mode = Addressing_Constant; + operand->value = exact_value_quaternion(0.0, 0.0, 0.0, 0.0); + break; + } + // quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type - Operand x = *operand; + Operand x = {}; Operand y = {}; Operand z = {}; Operand w = {}; @@ -2309,23 +2338,103 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = t_invalid; operand->mode = Addressing_Invalid; - check_expr(c, &y, ce->args[1]); - if (y.mode == Addressing_Invalid) { - return false; - } - check_expr(c, &z, ce->args[2]); - if (y.mode == Addressing_Invalid) { - return false; - } - check_expr(c, &w, ce->args[3]); - if (y.mode == Addressing_Invalid) { - return false; - } + if (first_is_field_value) { + u32 fields_set[4] = {}; // 0 unset, 1 xyzw, 2 real/etc + + auto const check_field = [&fields_set, &builtin_name](CheckerContext *c, Operand *o, Ast *arg, i32 *index) -> bool { + *index = -1; + + ast_node(field, FieldValue, arg); + String name = {}; + if (field->field->kind == Ast_Ident) { + name = field->field->Ident.token.string; + } else { + error(field->field, "Expected an identifier for field argument"); + return false; + } + + u32 style = 0; + + if (name == "x") { + *index = 1; style = 1; + } else if (name == "y") { + *index = 2; style = 1; + } else if (name == "z") { + *index = 3; style = 1; + } else if (name == "w") { + *index = 0; style = 1; + } else if (name == "imag") { + *index = 1; style = 2; + } else if (name == "jmag") { + *index = 2; style = 2; + } else if (name == "kmag") { + *index = 3; style = 2; + } else if (name == "real") { + *index = 0; style = 2; + } else { + error(field->field, "Unknown name for '%.*s', expected (w, x, y, z; or real, imag, jmag, kmag), got '%.*s'", LIT(builtin_name), LIT(name)); + return false; + } + + if (fields_set[*index]) { + error(field->field, "Previously assigned field: '%.*s'", LIT(name)); + } + fields_set[*index] = style; + + check_expr(c, o, field->value); + return o->mode != Addressing_Invalid; + }; + + // TODO(bill): disallow style mixing + Operand *refs[4] = {&x, &y, &z, &w}; + + for (i32 i = 0; i < 4; i++) { + i32 index = -1; + Operand o = {}; + bool ok = check_field(c, &o, ce->args[i], &index); + if (!ok) { + return false; + } + + *refs[index] = o; + } + + for (i32 i = 0; i < 4; i++) { + GB_ASSERT(fields_set[i]); + } + for (i32 i = 1; i < 4; i++) { + if (fields_set[i] != fields_set[i-1]) { + error(call, "Mixture of xyzw and real/etc is not allowed with '%.*s'", LIT(builtin_name)); + break; + } + } + } else { + error(call, "'%.*s' requires that all arguments are named (w, x, y, z; or real, imag, jmag, kmag)", LIT(builtin_name)); + + check_expr(c, &x, ce->args[0]); + if (x.mode == Addressing_Invalid) { + return false; + } + + check_expr(c, &y, ce->args[1]); + if (y.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &z, ce->args[2]); + if (z.mode == Addressing_Invalid) { + return false; + } + check_expr(c, &w, ce->args[3]); + if (w.mode == Addressing_Invalid) { + return false; + } + } convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false; convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false; convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false; convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false; + if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && z.mode == Addressing_Constant && @@ -3092,7 +3201,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As mix = arg->kind == Ast_FieldValue; } if (mix) { - error(arg, "Mixture of 'field = value' and value elements in the procedure call 'soa_zip' is not allowed"); + error(arg, "Mixture of 'field = value' and value elements in the procedure call '%.*s' is not allowed", LIT(builtin_name)); fail = true; break; } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 1244bd377..3f16d07a5 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1826,24 +1826,41 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } case BuiltinProc_quaternion: { - lbValue real = lb_build_expr(p, ce->args[0]); - lbValue imag = lb_build_expr(p, ce->args[1]); - lbValue jmag = lb_build_expr(p, ce->args[2]); - lbValue kmag = lb_build_expr(p, ce->args[3]); + lbValue xyzw[4] = {}; + for (i32 i = 0; i < 4; i++) { + ast_node(f, FieldValue, ce->args[i]); + GB_ASSERT(f->field->kind == Ast_Ident); + String name = f->field->Ident.token.string; + i32 index = -1; + + // @QuaternionLayout + if (name == "x" || name == "imag") { + index = 0; + } else if (name == "y" || name == "jmag") { + index = 1; + } else if (name == "z" || name == "kmag") { + index = 2; + } else if (name == "w" || name == "real") { + index = 3; + } + GB_ASSERT(index >= 0); + + xyzw[index] = lb_build_expr(p, ce->args[i]); + } + - // @QuaternionLayout lbAddr dst_addr = lb_add_local_generated(p, tv.type, false); lbValue dst = lb_addr_get_ptr(p, dst_addr); Type *ft = base_complex_elem_type(tv.type); - real = lb_emit_conv(p, real, ft); - imag = lb_emit_conv(p, imag, ft); - jmag = lb_emit_conv(p, jmag, ft); - kmag = lb_emit_conv(p, kmag, ft); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), real); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), imag); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), jmag); - lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), kmag); + xyzw[0] = lb_emit_conv(p, xyzw[0], ft); + xyzw[1] = lb_emit_conv(p, xyzw[1], ft); + xyzw[2] = lb_emit_conv(p, xyzw[2], ft); + xyzw[3] = lb_emit_conv(p, xyzw[3], ft); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), xyzw[0]); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), xyzw[1]); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), xyzw[2]); + lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), xyzw[3]); return lb_emit_load(p, dst); } -- cgit v1.2.3 From 3bf7b416e72259059a91a785d70b50961f6c41c6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Jan 2024 14:36:58 +0000 Subject: Fix `builtin.quaternion` generation --- core/builtin/builtin.odin | 2 +- src/check_builtin.cpp | 126 ++++++++++++++++++++-------------------------- src/llvm_backend_proc.cpp | 2 +- 3 files changed, 56 insertions(+), 74 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/core/builtin/builtin.odin b/core/builtin/builtin.odin index 211db9770..5cba3c8ea 100644 --- a/core/builtin/builtin.odin +++ b/core/builtin/builtin.odin @@ -110,7 +110,7 @@ typeid_of :: proc($T: typeid) -> typeid --- swizzle :: proc(x: [N]T, indices: ..int) -> [len(indices)]T --- complex :: proc(real, imag: Float) -> Complex_Type --- -quaternion :: proc(real, imag, jmag, kmag: Float) -> Quaternion_Type --- +quaternion :: proc(imag, jmag, kmag, real: Float) -> Quaternion_Type --- // fields must be named real :: proc(value: Complex_Or_Quaternion) -> Float --- imag :: proc(value: Complex_Or_Quaternion) -> Float --- jmag :: proc(value: Quaternion) -> Float --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 55962f89f..0b3d65f78 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2328,11 +2328,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } - // quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type - Operand x = {}; - Operand y = {}; - Operand z = {}; - Operand w = {}; + // quaternion :: proc(imag, jmag, kmag, real: float_type) -> complex_type + Operand xyzw[4] = {}; // NOTE(bill): Invalid will be the default till fixed operand->type = t_invalid; @@ -2356,21 +2353,21 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As u32 style = 0; if (name == "x") { - *index = 1; style = 1; + *index = 0; style = 1; } else if (name == "y") { - *index = 2; style = 1; + *index = 1; style = 1; } else if (name == "z") { - *index = 3; style = 1; + *index = 2; style = 1; } else if (name == "w") { - *index = 0; style = 1; + *index = 3; style = 1; } else if (name == "imag") { - *index = 1; style = 2; + *index = 0; style = 2; } else if (name == "jmag") { - *index = 2; style = 2; + *index = 1; style = 2; } else if (name == "kmag") { - *index = 3; style = 2; + *index = 2; style = 2; } else if (name == "real") { - *index = 0; style = 2; + *index = 3; style = 2; } else { error(field->field, "Unknown name for '%.*s', expected (w, x, y, z; or real, imag, jmag, kmag), got '%.*s'", LIT(builtin_name), LIT(name)); return false; @@ -2385,9 +2382,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return o->mode != Addressing_Invalid; }; - // TODO(bill): disallow style mixing - - Operand *refs[4] = {&x, &y, &z, &w}; + Operand *refs[4] = {&xyzw[0], &xyzw[1], &xyzw[2], &xyzw[3]}; for (i32 i = 0; i < 4; i++) { i32 index = -1; @@ -2412,57 +2407,40 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } else { error(call, "'%.*s' requires that all arguments are named (w, x, y, z; or real, imag, jmag, kmag)", LIT(builtin_name)); - check_expr(c, &x, ce->args[0]); - if (x.mode == Addressing_Invalid) { - return false; - } - - check_expr(c, &y, ce->args[1]); - if (y.mode == Addressing_Invalid) { - return false; - } - check_expr(c, &z, ce->args[2]); - if (z.mode == Addressing_Invalid) { - return false; - } - check_expr(c, &w, ce->args[3]); - if (w.mode == Addressing_Invalid) { - return false; + for (i32 i = 0; i < 4; i++) { + check_expr(c, &xyzw[i], ce->args[i]); + if (xyzw[i].mode == Addressing_Invalid) { + return false; + } } } - convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false; - convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false; - convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false; - convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false; + convert_to_typed(c, &xyzw[0], xyzw[1].type); if (xyzw[0].mode == Addressing_Invalid) return false; + convert_to_typed(c, &xyzw[1], xyzw[0].type); if (xyzw[1].mode == Addressing_Invalid) return false; + convert_to_typed(c, &xyzw[2], xyzw[0].type); if (xyzw[2].mode == Addressing_Invalid) return false; + convert_to_typed(c, &xyzw[3], xyzw[0].type); if (xyzw[3].mode == Addressing_Invalid) return false; - if (x.mode == Addressing_Constant && - y.mode == Addressing_Constant && - z.mode == Addressing_Constant && - w.mode == Addressing_Constant) { - x.value = exact_value_to_float(x.value); - y.value = exact_value_to_float(y.value); - z.value = exact_value_to_float(z.value); - w.value = exact_value_to_float(w.value); - if (is_type_numeric(x.type) && x.value.kind == ExactValue_Float) { - x.type = t_untyped_float; - } - if (is_type_numeric(y.type) && y.value.kind == ExactValue_Float) { - y.type = t_untyped_float; - } - if (is_type_numeric(z.type) && z.value.kind == ExactValue_Float) { - z.type = t_untyped_float; + if (xyzw[0].mode == Addressing_Constant && + xyzw[1].mode == Addressing_Constant && + xyzw[2].mode == Addressing_Constant && + xyzw[3].mode == Addressing_Constant) { + for (i32 i = 0; i < 4; i++) { + xyzw[i].value = exact_value_to_float(xyzw[i].value); } - if (is_type_numeric(w.type) && w.value.kind == ExactValue_Float) { - w.type = t_untyped_float; + for (i32 i = 0; i < 4; i++) { + if (is_type_numeric(xyzw[i].type) && xyzw[i].value.kind == ExactValue_Float) { + xyzw[i].type = t_untyped_float; + } } } - if (!(are_types_identical(x.type, y.type) && are_types_identical(x.type, z.type) && are_types_identical(x.type, w.type))) { - gbString tx = type_to_string(x.type); - gbString ty = type_to_string(y.type); - gbString tz = type_to_string(z.type); - gbString tw = type_to_string(w.type); - error(call, "Mismatched types to 'quaternion', '%s' vs '%s' vs '%s' vs '%s'", tx, ty, tz, tw); + if (!(are_types_identical(xyzw[0].type, xyzw[1].type) && + are_types_identical(xyzw[0].type, xyzw[2].type) && + are_types_identical(xyzw[0].type, xyzw[3].type))) { + gbString tx = type_to_string(xyzw[0].type); + gbString ty = type_to_string(xyzw[1].type); + gbString tz = type_to_string(xyzw[2].type); + gbString tw = type_to_string(xyzw[3].type); + error(call, "Mismatched types to 'quaternion', 'x=%s' vs 'y=%s' vs 'z=%s' vs 'w=%s'", tx, ty, tz, tw); gb_string_free(tw); gb_string_free(tz); gb_string_free(ty); @@ -2470,31 +2448,35 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } - if (!is_type_float(x.type)) { - gbString s = type_to_string(x.type); + if (!is_type_float(xyzw[0].type)) { + gbString s = type_to_string(xyzw[0].type); error(call, "Arguments have type '%s', expected a floating point", s); gb_string_free(s); return false; } - if (is_type_endian_specific(x.type)) { - gbString s = type_to_string(x.type); + if (is_type_endian_specific(xyzw[0].type)) { + gbString s = type_to_string(xyzw[0].type); error(call, "Arguments with a specified endian are not allow, expected a normal floating point, got '%s'", s); gb_string_free(s); return false; } - if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && z.mode == Addressing_Constant && w.mode == Addressing_Constant) { - f64 r = exact_value_to_float(x.value).value_float; - f64 i = exact_value_to_float(y.value).value_float; - f64 j = exact_value_to_float(z.value).value_float; - f64 k = exact_value_to_float(w.value).value_float; + + operand->mode = Addressing_Value; + + if (xyzw[0].mode == Addressing_Constant && + xyzw[1].mode == Addressing_Constant && + xyzw[2].mode == Addressing_Constant && + xyzw[3].mode == Addressing_Constant) { + f64 r = exact_value_to_float(xyzw[3].value).value_float; + f64 i = exact_value_to_float(xyzw[0].value).value_float; + f64 j = exact_value_to_float(xyzw[1].value).value_float; + f64 k = exact_value_to_float(xyzw[2].value).value_float; operand->value = exact_value_quaternion(r, i, j, k); operand->mode = Addressing_Constant; - } else { - operand->mode = Addressing_Value; } - BasicKind kind = core_type(x.type)->Basic.kind; + BasicKind kind = core_type(xyzw[0].type)->Basic.kind; switch (kind) { case Basic_f16: operand->type = t_quaternion64; break; case Basic_f32: operand->type = t_quaternion128; break; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 3f16d07a5..d4eae84bc 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1845,7 +1845,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } GB_ASSERT(index >= 0); - xyzw[index] = lb_build_expr(p, ce->args[i]); + xyzw[index] = lb_build_expr(p, f->value); } -- cgit v1.2.3 From 8545f316ffa37c2c9fedb1808a4a3d59b0088707 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Jan 2024 14:45:03 +0000 Subject: Fix the type inference in `builtin.quaternion` --- src/check_builtin.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 0b3d65f78..09ca0bc23 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2331,6 +2331,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As // quaternion :: proc(imag, jmag, kmag, real: float_type) -> complex_type Operand xyzw[4] = {}; + u32 first_index = 0; + // NOTE(bill): Invalid will be the default till fixed operand->type = t_invalid; operand->mode = Addressing_Invalid; @@ -2388,10 +2390,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As i32 index = -1; Operand o = {}; bool ok = check_field(c, &o, ce->args[i], &index); - if (!ok) { + if (!ok || index < 0) { return false; } - + first_index = cast(u32)index; *refs[index] = o; } @@ -2414,11 +2416,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } } } - convert_to_typed(c, &xyzw[0], xyzw[1].type); if (xyzw[0].mode == Addressing_Invalid) return false; - convert_to_typed(c, &xyzw[1], xyzw[0].type); if (xyzw[1].mode == Addressing_Invalid) return false; - convert_to_typed(c, &xyzw[2], xyzw[0].type); if (xyzw[2].mode == Addressing_Invalid) return false; - convert_to_typed(c, &xyzw[3], xyzw[0].type); if (xyzw[3].mode == Addressing_Invalid) return false; + + for (u32 i = 0; i < 4; i++ ){ + u32 j = (i + first_index) % 4; + if (j == first_index) { + convert_to_typed(c, &xyzw[j], xyzw[(first_index+1)%4].type); if (xyzw[j].mode == Addressing_Invalid) return false; + } else { + convert_to_typed(c, &xyzw[j], xyzw[first_index].type); if (xyzw[j].mode == Addressing_Invalid) return false; + } + } if (xyzw[0].mode == Addressing_Constant && xyzw[1].mode == Addressing_Constant && xyzw[2].mode == Addressing_Constant && @@ -2476,7 +2483,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->mode = Addressing_Constant; } - BasicKind kind = core_type(xyzw[0].type)->Basic.kind; + BasicKind kind = core_type(xyzw[first_index].type)->Basic.kind; switch (kind) { case Basic_f16: operand->type = t_quaternion64; break; case Basic_f32: operand->type = t_quaternion128; break; -- cgit v1.2.3 From bf90b61908661ad314206e5d37769004289ed070 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 2 Feb 2024 14:52:42 +0000 Subject: Fix `type_elem_type` for `complex32` and `quaternion64` --- src/check_builtin.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 09ca0bc23..e1cb43ec1 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4892,8 +4892,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As switch (bt->kind) { case Type_Basic: switch (bt->Basic.kind) { + case Basic_complex32: operand->type = t_f16; break; case Basic_complex64: operand->type = t_f32; break; case Basic_complex128: operand->type = t_f64; break; + case Basic_quaternion64: operand->type = t_f16; break; case Basic_quaternion128: operand->type = t_f32; break; case Basic_quaternion256: operand->type = t_f64; break; } -- cgit v1.2.3 From 59933b244ded0ab2476535b18875de95cd9f47bc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 8 Feb 2024 13:41:02 +0000 Subject: Allow polymorphic checking with `intrinsics.type_is_subtype_of(Derived_Type, Poly_Type)` --- src/check_builtin.cpp | 2 +- src/check_type.cpp | 14 ++++++++++++-- src/types.cpp | 19 +++++++++++++++++-- 3 files changed, 30 insertions(+), 5 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index e1cb43ec1..4e374add6 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5686,7 +5686,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } - operand->value = exact_value_bool(is_type_subtype_of(op_src.type, op_dst.type)); + operand->value = exact_value_bool(is_type_subtype_of_and_allow_polymorphic(op_src.type, op_dst.type)); operand->mode = Addressing_Constant; operand->type = t_untyped_bool; } break; diff --git a/src/check_type.cpp b/src/check_type.cpp index 4d0901605..15bba5319 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1,5 +1,6 @@ gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location); gb_internal Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand const &operand); +gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array const *operands); gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) { t = base_type(t); @@ -394,7 +395,6 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly bool *is_polymorphic_, Ast *node, Array *poly_operands) { Type *polymorphic_params_type = nullptr; - bool can_check_fields = true; GB_ASSERT(is_polymorphic_ != nullptr); if (polymorphic_params == nullptr) { @@ -404,6 +404,17 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly return polymorphic_params_type; } + + // bool is_variadic = false; + // isize variadic_index = 0; + // bool success = false; + // isize specialization_count = 0; + // polymorphic_params_type = check_get_params(ctx, ctx->scope, polymorphic_params, &is_variadic, &variadic_index, &success, &specialization_count, poly_operands); + // if (success) { + // return nullptr; + // } + + bool can_check_fields = true; ast_node(field_list, FieldList, polymorphic_params); Slice params = field_list->list; if (params.count != 0) { @@ -565,7 +576,6 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly if (!*is_polymorphic_) { *is_polymorphic_ = polymorphic_params != nullptr && poly_operands == nullptr; } - return polymorphic_params_type; } diff --git a/src/types.cpp b/src/types.cpp index b99d469e4..c4b03c967 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4093,7 +4093,7 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) { return offset; } -gb_internal isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0, bool src_is_ptr = false) { +gb_internal isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0, bool src_is_ptr = false, bool allow_polymorphic=false) { Type *prev_src = src; src = type_deref(src); if (!src_is_ptr) { @@ -4105,11 +4105,19 @@ gb_internal isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isi return 0; } + bool dst_is_polymorphic = is_type_polymorphic(dst); + for_array(i, src->Struct.fields) { Entity *f = src->Struct.fields[i]; if (f->kind != Entity_Variable || (f->flags&EntityFlags_IsSubtype) == 0) { continue; } + if (allow_polymorphic && dst_is_polymorphic) { + Type *fb = base_type(type_deref(f->type)); + if (fb->kind == Type_Struct && fb->Struct.polymorphic_parent == dst) { + return true; + } + } if (are_types_identical(f->type, dst)) { return level+1; @@ -4119,7 +4127,7 @@ gb_internal isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isi return level+1; } } - isize nested_level = check_is_assignable_to_using_subtype(f->type, dst, level+1, src_is_ptr); + isize nested_level = check_is_assignable_to_using_subtype(f->type, dst, level+1, src_is_ptr, allow_polymorphic); if (nested_level > 0) { return nested_level; } @@ -4135,6 +4143,13 @@ gb_internal bool is_type_subtype_of(Type *src, Type *dst) { return 0 < check_is_assignable_to_using_subtype(src, dst, 0, is_type_pointer(src)); } +gb_internal bool is_type_subtype_of_and_allow_polymorphic(Type *src, Type *dst) { + if (are_types_identical(src, dst)) { + return true; + } + + return 0 < check_is_assignable_to_using_subtype(src, dst, 0, is_type_pointer(src), true); +} gb_internal bool has_type_got_objc_class_attribute(Type *t) { -- cgit v1.2.3 From 5c4485f65767366c14dfd9a98945a5479ae0e449 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 9 Feb 2024 15:18:29 +0000 Subject: Add `#load_directory(path: string) > []runtime.Load_Directory_File` --- base/runtime/core.odin | 8 ++ src/check_builtin.cpp | 187 +++++++++++++++++++++++++++++++++------------- src/check_expr.cpp | 5 +- src/checker.cpp | 15 ++++ src/checker.hpp | 18 +++++ src/llvm_backend_proc.cpp | 67 +++++++++++++---- src/string.cpp | 12 +++ src/types.cpp | 4 + 8 files changed, 247 insertions(+), 69 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index fbdf33085..85e64242d 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -296,6 +296,14 @@ Source_Code_Location :: struct { procedure: string, } +/* + Used by the built-in directory `#load_directory(path: string) -> []Load_Directory_File` +*/ +Load_Directory_File :: struct { + name: string, + data: []byte, // immutable data +} + Assertion_Failure_Proc :: #type proc(prefix, message: string, loc: Source_Code_Location) -> ! // Allocation Stuff diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 4e374add6..d39be37a9 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1264,6 +1264,139 @@ gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand } +gb_internal int file_cache_sort_cmp(void const *x, void const *y) { + LoadFileCache const *a = *(LoadFileCache const **)(x); + LoadFileCache const *b = *(LoadFileCache const **)(y); + return string_compare(a->path, b->path); +} + +gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) { + ast_node(ce, CallExpr, call); + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + GB_ASSERT(name == "load_directory"); + + if (ce->args.count != 1) { + error(ce->args[0], "'#%.*s' expects 1 argument, got %td", LIT(name), ce->args.count); + return LoadDirective_Error; + } + + Ast *arg = ce->args[0]; + Operand o = {}; + check_expr(c, &o, arg); + if (o.mode != Addressing_Constant) { + error(arg, "'#%.*s' expected a constant string argument", LIT(name)); + return LoadDirective_Error; + } + + if (!is_type_string(o.type)) { + gbString str = type_to_string(o.type); + error(arg, "'#%.*s' expected a constant string, got %s", LIT(name), str); + gb_string_free(str); + return LoadDirective_Error; + } + + GB_ASSERT(o.value.kind == ExactValue_String); + + init_core_load_directory_file(c->checker); + + operand->type = t_load_directory_file_slice; + operand->mode = Addressing_Value; + + + String original_string = o.value.value_string; + String path; + if (gb_path_is_absolute((char*)original_string.text)) { + path = original_string; + } else { + String base_dir = dir_from_path(get_file_path_string(call->file_id)); + + BlockingMutex *ignore_mutex = nullptr; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + } + MUTEX_GUARD(&c->info->load_directory_mutex); + + + gbFileError file_error = gbFileError_None; + + Array file_caches = {}; + + LoadDirectoryCache **cache_ptr = string_map_get(&c->info->load_directory_cache, path); + LoadDirectoryCache *cache = cache_ptr ? *cache_ptr : nullptr; + if (cache) { + file_error = cache->file_error; + } + defer ({ + if (cache == nullptr) { + LoadDirectoryCache *new_cache = gb_alloc_item(permanent_allocator(), LoadDirectoryCache); + new_cache->path = path; + new_cache->files = file_caches; + new_cache->file_error = file_error; + string_map_set(&c->info->load_directory_cache, path, new_cache); + + map_set(&c->info->load_directory_map, call, new_cache); + } else { + cache->file_error = file_error; + } + }); + + + LoadDirectiveResult result = LoadDirective_Success; + + + if (cache == nullptr) { + Array list = {}; + ReadDirectoryError rd_err = read_directory(path, &list); + defer (array_free(&list)); + + if (list.count == 1) { + GB_ASSERT(path != list[0].fullpath); + } + + + switch (rd_err) { + case ReadDirectory_InvalidPath: + error(call, "%.*s error - invalid path: %.*s", LIT(name), LIT(original_string)); + return LoadDirective_NotFound; + case ReadDirectory_NotExists: + error(call, "%.*s error - path does not exist: %.*s", LIT(name), LIT(original_string)); + return LoadDirective_NotFound; + case ReadDirectory_Permission: + error(call, "%.*s error - unknown error whilst reading path, %.*s", LIT(name), LIT(original_string)); + return LoadDirective_Error; + case ReadDirectory_NotDir: + error(call, "%.*s error - expected a directory, got a file: %.*s", LIT(name), LIT(original_string)); + return LoadDirective_Error; + case ReadDirectory_Empty: + error(call, "%.*s error - empty directory: %.*s", LIT(name), LIT(original_string)); + return LoadDirective_NotFound; + case ReadDirectory_Unknown: + error(call, "%.*s error - unknown error whilst reading path %.*s", LIT(name), LIT(original_string)); + return LoadDirective_Error; + } + + isize files_to_reserve = list.count+1; // always reserve 1 + + file_caches = array_make(heap_allocator(), 0, files_to_reserve); + + for (FileInfo fi : list) { + LoadFileCache *cache = nullptr; + if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache)) { + array_add(&file_caches, cache); + } else { + result = LoadDirective_Error; + } + } + + gb_sort_array(file_caches.data, file_caches.count, file_cache_sort_cmp); + + } + + return result; +} + + gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) { ast_node(ce, CallExpr, call); @@ -1291,6 +1424,8 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o operand->mode = Addressing_Value; } else if (name == "load") { return check_load_directive(c, operand, call, type_hint, true) == LoadDirective_Success; + } else if (name == "load_directory") { + return check_load_directory_directive(c, operand, call, type_hint, true) == LoadDirective_Success; } else if (name == "load_hash") { if (ce->args.count != 2) { if (ce->args.count == 0) { @@ -1408,58 +1543,6 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o return true; } return false; - } else if (name == "load_or") { - error(call, "'#load_or' has now been removed in favour of '#load(path) or_else default'"); - - if (ce->args.count != 2) { - if (ce->args.count == 0) { - error(ce->close, "'#load_or' expects 2 arguments, got 0"); - } else { - error(ce->args[0], "'#load_or' expects 2 arguments, got %td", ce->args.count); - } - return false; - } - - Ast *arg = ce->args[0]; - Operand o = {}; - check_expr(c, &o, arg); - if (o.mode != Addressing_Constant) { - error(arg, "'#load_or' expected a constant string argument"); - return false; - } - - if (!is_type_string(o.type)) { - gbString str = type_to_string(o.type); - error(arg, "'#load_or' expected a constant string, got %s", str); - gb_string_free(str); - return false; - } - - Ast *default_arg = ce->args[1]; - Operand default_op = {}; - check_expr_with_type_hint(c, &default_op, default_arg, t_u8_slice); - if (default_op.mode != Addressing_Constant) { - error(arg, "'#load_or' expected a constant '[]byte' argument"); - return false; - } - - if (!are_types_identical(base_type(default_op.type), t_u8_slice)) { - gbString str = type_to_string(default_op.type); - error(arg, "'#load_or' expected a constant '[]byte', got %s", str); - gb_string_free(str); - return false; - } - GB_ASSERT(o.value.kind == ExactValue_String); - String original_string = o.value.value_string; - - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; - LoadFileCache *cache = nullptr; - if (cache_load_file_directive(c, call, original_string, false, &cache)) { - operand->value = exact_value_string(cache->data); - } else { - operand->value = default_op.value; - } } else if (name == "assert") { if (ce->args.count != 1 && ce->args.count != 2) { error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9b71208cd..11eb4b533 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7107,8 +7107,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c name == "defined" || name == "config" || name == "load" || - name == "load_hash" || - name == "load_or" + name == "load_directory" || + name == "load_hash" ) { operand->mode = Addressing_Builtin; operand->builtin_id = BuiltinProc_DIRECTIVE; @@ -7958,6 +7958,7 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A name == "config" || name == "load" || name == "load_hash" || + name == "load_directory" || name == "load_or" ) { error(node, "'#%.*s' must be used as a call", LIT(name)); diff --git a/src/checker.cpp b/src/checker.cpp index 457ee6146..569a3c76f 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1257,6 +1257,9 @@ gb_internal void init_checker_info(CheckerInfo *i) { mpsc_init(&i->required_global_variable_queue, a); // 1<<10); mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10); mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used + + string_map_init(&i->load_directory_cache); + map_init(&i->load_directory_map); } gb_internal void destroy_checker_info(CheckerInfo *i) { @@ -1280,6 +1283,8 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { map_destroy(&i->objc_msgSend_types); string_map_destroy(&i->load_file_cache); + string_map_destroy(&i->load_directory_cache); + map_destroy(&i->load_directory_map); } gb_internal CheckerContext make_checker_context(Checker *c) { @@ -2958,6 +2963,16 @@ gb_internal void init_core_source_code_location(Checker *c) { t_source_code_location_ptr = alloc_type_pointer(t_source_code_location); } +gb_internal void init_core_load_directory_file(Checker *c) { + if (t_load_directory_file != nullptr) { + return; + } + t_load_directory_file = find_core_type(c, str_lit("Load_Directory_File")); + t_load_directory_file_ptr = alloc_type_pointer(t_load_directory_file); + t_load_directory_file_slice = alloc_type_slice(t_load_directory_file); +} + + gb_internal void init_core_map_type(Checker *c) { if (t_map_info != nullptr) { return; diff --git a/src/checker.hpp b/src/checker.hpp index 9da0f2950..9aee82257 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -340,6 +340,19 @@ struct LoadFileCache { StringMap hashes; }; + +struct LoadDirectoryFile { + String file_name; + String data; +}; + +struct LoadDirectoryCache { + String path; + gbFileError file_error; + Array files; +}; + + struct GenProcsData { Array procs; RwMutex mutex; @@ -416,6 +429,11 @@ struct CheckerInfo { BlockingMutex instrumentation_mutex; Entity *instrumentation_enter_entity; Entity *instrumentation_exit_entity; + + + BlockingMutex load_directory_mutex; + StringMap load_directory_cache; + PtrMap load_directory_map; // Key: Ast_CallExpr * }; struct CheckerContext { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index e0aca2c10..9419f9a3c 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1693,24 +1693,61 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_DIRECTIVE: { ast_node(bd, BasicDirective, ce->proc); String name = bd->name.string; - GB_ASSERT(name == "location"); - String procedure = p->entity->token.string; - TokenPos pos = ast_token(ce->proc).pos; - if (ce->args.count > 0) { - Ast *ident = unselector_expr(ce->args[0]); - GB_ASSERT(ident->kind == Ast_Ident); - Entity *e = entity_of_node(ident); - GB_ASSERT(e != nullptr); - - if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) { - procedure = e->parent_proc_decl->entity->token.string; - } else { - procedure = str_lit(""); + if (name == "location") { + String procedure = p->entity->token.string; + TokenPos pos = ast_token(ce->proc).pos; + if (ce->args.count > 0) { + Ast *ident = unselector_expr(ce->args[0]); + GB_ASSERT(ident->kind == Ast_Ident); + Entity *e = entity_of_node(ident); + GB_ASSERT(e != nullptr); + + if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) { + procedure = e->parent_proc_decl->entity->token.string; + } else { + procedure = str_lit(""); + } + pos = e->token.pos; + } - pos = e->token.pos; + return lb_emit_source_code_location_as_global(p, procedure, pos); + } else if (name == "load_directory") { + lbModule *m = p->module; + TEMPORARY_ALLOCATOR_GUARD(); + LoadDirectoryCache *cache = map_must_get(&m->info->load_directory_map, expr); + isize count = cache->files.count; + + LLVMValueRef *elements = gb_alloc_array(temporary_allocator(), LLVMValueRef, count); + for_array(i, cache->files) { + LoadFileCache *file = cache->files[i]; + String file_name = filename_without_directory(file->path); + + LLVMValueRef values[2] = {}; + values[0] = lb_const_string(m, file_name).value; + values[1] = lb_const_string(m, file->data).value; + LLVMValueRef element = llvm_const_named_struct(m, t_load_directory_file, values, gb_count_of(values)); + elements[i] = element; + } + + LLVMValueRef backing_array = llvm_const_array(lb_type(m, t_load_directory_file), elements, count); + + Type *array_type = alloc_type_array(t_load_directory_file, count); + lbAddr backing_array_addr = lb_add_global_generated(m, array_type, {backing_array, array_type}, nullptr); + lb_make_global_private_const(backing_array_addr); + + LLVMValueRef backing_array_ptr = backing_array_addr.addr.value; + backing_array_ptr = LLVMConstPointerCast(backing_array_ptr, lb_type(m, t_load_directory_file_ptr)); + + LLVMValueRef const_slice = llvm_const_slice_internal(m, backing_array_ptr, LLVMConstInt(lb_type(m, t_int), count, false)); + + lbAddr addr = lb_add_global_generated(p->module, tv.type, {const_slice, t_load_directory_file_slice}, nullptr); + lb_make_global_private_const(addr); + + return lb_addr_load(p, addr); + } else { + GB_PANIC("UNKNOWN DIRECTIVE: %.*s", LIT(name)); } - return lb_emit_source_code_location_as_global(p, procedure, pos); } case BuiltinProc_type_info_of: { diff --git a/src/string.cpp b/src/string.cpp index 9fb933b1b..bd703b2a6 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -293,6 +293,18 @@ gb_internal String filename_from_path(String s) { return make_string(nullptr, 0); } + +gb_internal String filename_without_directory(String s) { + isize j = 0; + for (j = s.len-1; j >= 0; j--) { + if (s[j] == '/' || + s[j] == '\\') { + break; + } + } + return substring(s, gb_max(j+1, 0), s.len); +} + gb_internal String concatenate_strings(gbAllocator a, String const &x, String const &y) { isize len = x.len+y.len; u8 *data = gb_alloc_array(a, u8, len+1); diff --git a/src/types.cpp b/src/types.cpp index c4b03c967..8275b87ba 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -679,6 +679,10 @@ gb_global Type *t_allocator_error = nullptr; gb_global Type *t_source_code_location = nullptr; gb_global Type *t_source_code_location_ptr = nullptr; +gb_global Type *t_load_directory_file = nullptr; +gb_global Type *t_load_directory_file_ptr = nullptr; +gb_global Type *t_load_directory_file_slice = nullptr; + gb_global Type *t_map_info = nullptr; gb_global Type *t_map_cell_info = nullptr; gb_global Type *t_raw_map = nullptr; -- cgit v1.2.3 From a642ea0b28f8b1edad247b484ae000f20218347d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 23 Feb 2024 11:38:23 +0000 Subject: Add `intrinsics.type_bit_set_backing_type` --- src/check_builtin.cpp | 20 ++++++++++++++++++++ src/checker_builtin_procs.hpp | 4 ++++ 2 files changed, 24 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index d39be37a9..c85fb28d6 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5820,6 +5820,26 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; + case BuiltinProc_type_bit_set_backing_type: + { + Operand op = {}; + Type *type = check_type(c, ce->args[0]); + Type *bt = base_type(type); + if (bt == nullptr || bt == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (bt->kind != Type_BitSet) { + gbString s = type_to_string(type); + error(ce->args[0], "Expected a bit_set type for '%.*s', got %s", LIT(builtin_name), s); + return false; + } + + operand->mode = Addressing_Type; + operand->type = bit_set_to_int(bt); + break; + } + case BuiltinProc_type_equal_proc: { Operand op = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 42ffa6938..c15ec7137 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -282,6 +282,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_field_index_of, + BuiltinProc_type_bit_set_backing_type, + BuiltinProc_type_equal_proc, BuiltinProc_type_hasher_proc, BuiltinProc_type_map_info, @@ -586,6 +588,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_bit_set_backing_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_hasher_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_map_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From 88add0b6b12b6590fd69bb74182f1a7689ae9ff6 Mon Sep 17 00:00:00 2001 From: avanspector Date: Sun, 25 Feb 2024 02:24:52 +0100 Subject: Improve Haiku support --- src/build_settings.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/check_builtin.cpp | 1 + src/checker.cpp | 1 + src/linker.cpp | 4 +-- src/llvm_backend.cpp | 4 +-- src/tilde.cpp | 1 + 6 files changed, 73 insertions(+), 4 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 0bcb9f298..f395cb515 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -18,6 +18,7 @@ enum TargetOsKind : u16 { TargetOs_essence, TargetOs_freebsd, TargetOs_openbsd, + TargetOs_haiku, TargetOs_wasi, TargetOs_js, @@ -542,6 +543,13 @@ gb_global TargetMetrics target_openbsd_amd64 = { str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"), }; +gb_global TargetMetrics target_haiku_amd64 = { + TargetOs_haiku, + TargetArch_amd64, + 8, 8, 8, 16, + str_lit("x86_64-unknown-haiku"), +}; + gb_global TargetMetrics target_essence_amd64 = { TargetOs_essence, TargetArch_amd64, @@ -641,6 +649,7 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("freebsd_amd64"), &target_freebsd_amd64 }, { str_lit("openbsd_amd64"), &target_openbsd_amd64 }, + { str_lit("haiku_amd64"), &target_haiku_amd64 }, { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 }, { str_lit("wasi_wasm32"), &target_wasi_wasm32 }, @@ -872,6 +881,58 @@ gb_internal String internal_odin_root_dir(void) { return path; } +#elif defined(GB_SYSTEM_HAIKU) + +#include + +gb_internal String internal_odin_root_dir(void) { + String path = global_module_path; + isize len, i; + u8 *text; + + if (global_module_path_set) { + return global_module_path; + } + + auto path_buf = array_make(heap_allocator(), 300); + + len = 0; + for (;;) { + u32 sz = path_buf.count; + int res = find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, nullptr, &path_buf[0], sz); + if(res == B_OK) { + len = sz; + break; + } else { + array_resize(&path_buf, sz + 1); + } + } + + mutex_lock(&string_buffer_mutex); + defer (mutex_unlock(&string_buffer_mutex)); + + text = gb_alloc_array(permanent_allocator(), u8, len + 1); + gb_memmove(text, &path_buf[0], len); + + path = path_to_fullpath(heap_allocator(), make_string(text, len), nullptr); + + for (i = path.len-1; i >= 0; i--) { + u8 c = path[i]; + if (c == '/' || c == '\\') { + break; + } + path.len--; + } + + global_module_path = path; + global_module_path_set = true; + + + // array_free(&path_buf); + + return path; +} + #elif defined(GB_SYSTEM_OSX) #include @@ -1301,6 +1362,8 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta metrics = &target_freebsd_amd64; #elif defined(GB_SYSTEM_OPENBSD) metrics = &target_openbsd_amd64; + #elif defined(GB_SYSTEM_HAIKU) + metrics = &target_haiku_amd64; #elif defined(GB_CPU_ARM) metrics = &target_linux_arm64; #else @@ -1405,6 +1468,9 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta case TargetOs_openbsd: bc->link_flags = str_lit("-arch x86-64 "); break; + case TargetOs_haiku: + bc->link_flags = str_lit("-arch x86-64 "); + break; } } else if (bc->metrics.arch == TargetArch_i386) { switch (bc->metrics.os) { diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index d39be37a9..e00f6c053 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4928,6 +4928,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case TargetOs_essence: case TargetOs_freebsd: case TargetOs_openbsd: + case TargetOs_haiku: switch (build_context.metrics.arch) { case TargetArch_i386: case TargetArch_amd64: diff --git a/src/checker.cpp b/src/checker.cpp index 569a3c76f..b8b8e21e5 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1007,6 +1007,7 @@ gb_internal void init_universal(void) { {"Linux", TargetOs_linux}, {"Essence", TargetOs_essence}, {"FreeBSD", TargetOs_freebsd}, + {"Haiku", TargetOs_haiku}, {"OpenBSD", TargetOs_openbsd}, {"WASI", TargetOs_wasi}, {"JS", TargetOs_js}, diff --git a/src/linker.cpp b/src/linker.cpp index 987fab7f7..4e39f2ddc 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -474,8 +474,8 @@ gb_internal i32 linker_stage(LinkerData *gen) { link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); } - } else if (build_context.metrics.os != TargetOs_openbsd) { - // OpenBSD defaults to PIE executable. do not pass -no-pie for it. + } else if (build_context.metrics.os != TargetOs_openbsd && build_context.metrics.os != TargetOs_haiku) { + // OpenBSD and Haiku default to PIE executable. do not pass -no-pie for it. link_settings = gb_string_appendc(link_settings, "-no-pie "); } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index fa76ac22f..01d7a23b2 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2602,8 +2602,8 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { switch (build_context.reloc_mode) { case RelocMode_Default: - if (build_context.metrics.os == TargetOs_openbsd) { - // Always use PIC for OpenBSD: it defaults to PIE + if (build_context.metrics.os == TargetOs_openbsd || build_context.metrics.os == TargetOs_haiku) { + // Always use PIC for OpenBSD and Haiku: they default to PIE reloc_mode = LLVMRelocPIC; } break; diff --git a/src/tilde.cpp b/src/tilde.cpp index 06428f317..4fc7d1c9b 100644 --- a/src/tilde.cpp +++ b/src/tilde.cpp @@ -825,6 +825,7 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) { case TargetOs_essence: case TargetOs_freebsd: case TargetOs_openbsd: + case TargetOs_haiku: debug_format = TB_DEBUGFMT_DWARF; break; } -- cgit v1.2.3 From 9a2fc6cf4c8b4434ae45170953b77b3239120fea Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 19 Mar 2024 15:34:29 +0000 Subject: Serialize errors to make them sortable, deterministic, and generally more control --- src/array.cpp | 7 ++ src/build_settings.cpp | 4 + src/check_builtin.cpp | 2 +- src/check_expr.cpp | 2 +- src/checker.cpp | 8 +- src/common.cpp | 2 +- src/docs.cpp | 4 +- src/docs_writer.cpp | 2 +- src/error.cpp | 213 ++++++++++++++++++++++++++++++------------------- src/llvm_backend.cpp | 2 +- src/main.cpp | 4 +- src/string.cpp | 1 - 12 files changed, 158 insertions(+), 93 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/array.cpp b/src/array.cpp index 4583a31a9..ec2c97d0e 100644 --- a/src/array.cpp +++ b/src/array.cpp @@ -51,6 +51,13 @@ template gb_internal void array_copy(Array *array, Array cons template gb_internal T *array_end_ptr(Array *array); +template +gb_internal void array_sort(Array &array, gbCompareProc compare_proc) { + gb_sort_array(array.data, array.count, compare_proc); +} + + + template struct Slice { T *data; diff --git a/src/build_settings.cpp b/src/build_settings.cpp index fdaa971f1..c4073f329 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1272,6 +1272,10 @@ gb_internal String get_fullpath_core_collection(gbAllocator a, String path, bool gb_internal bool show_error_line(void) { return !build_context.hide_error_line; } + +gb_internal bool terse_errors(void) { + return build_context.terse_errors; +} gb_internal bool has_ansi_terminal_colours(void) { return build_context.has_ansi_terminal_colours; } diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index e1b1cd693..6de3b27f2 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1389,7 +1389,7 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c } } - gb_sort_array(file_caches.data, file_caches.count, file_cache_sort_cmp); + array_sort(file_caches, file_cache_sort_cmp); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 236d44a43..f359d5a54 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6485,7 +6485,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } if (valids.count > 1) { - gb_sort_array(valids.data, valids.count, valid_index_and_score_cmp); + array_sort(valids, valid_index_and_score_cmp); i64 best_score = valids[0].score; Entity *best_entity = proc_entities[valids[0].index]; GB_ASSERT(best_entity != nullptr); diff --git a/src/checker.cpp b/src/checker.cpp index fb7d401ab..836f803fc 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5044,7 +5044,7 @@ gb_internal void check_create_file_scopes(Checker *c) { for_array(i, c->parser->packages) { AstPackage *pkg = c->parser->packages[i]; - gb_sort_array(pkg->files.data, pkg->files.count, sort_file_by_name); + array_sort(pkg->files, sort_file_by_name); isize total_pkg_decl_count = 0; for_array(j, pkg->files) { @@ -5673,7 +5673,7 @@ gb_internal void remove_neighbouring_duplicate_entires_from_sorted_array(Arrayinfo.testing_procedures.data, c->info.testing_procedures.count, init_procedures_cmp); + array_sort(c->info.testing_procedures, init_procedures_cmp); remove_neighbouring_duplicate_entires_from_sorted_array(&c->info.testing_procedures); if (build_context.test_names.entries.count == 0) { @@ -6122,8 +6122,8 @@ gb_internal GB_COMPARE_PROC(fini_procedures_cmp) { } gb_internal void check_sort_init_and_fini_procedures(Checker *c) { - gb_sort_array(c->info.init_procedures.data, c->info.init_procedures.count, init_procedures_cmp); - gb_sort_array(c->info.fini_procedures.data, c->info.fini_procedures.count, fini_procedures_cmp); + array_sort(c->info.init_procedures, init_procedures_cmp); + array_sort(c->info.fini_procedures, fini_procedures_cmp); // NOTE(bill): remove possible duplicates from the init/fini lists // NOTE(bill): because the arrays are sorted, you only need to check the previous element diff --git a/src/common.cpp b/src/common.cpp index 90632def3..aad420325 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -913,7 +913,7 @@ gb_internal void did_you_mean_append(DidYouMeanAnswers *d, String const &target) array_add(&d->distances, dat); } gb_internal Slice did_you_mean_results(DidYouMeanAnswers *d) { - gb_sort_array(d->distances.data, d->distances.count, gb_isize_cmp(gb_offset_of(DistanceAndTarget, distance))); + array_sort(d->distances, gb_isize_cmp(gb_offset_of(DistanceAndTarget, distance))); isize count = 0; for (isize i = 0; i < d->distances.count; i++) { isize distance = d->distances[i].distance; diff --git a/src/docs.cpp b/src/docs.cpp index f00d4e15a..004134a5c 100644 --- a/src/docs.cpp +++ b/src/docs.cpp @@ -237,7 +237,7 @@ gb_internal void print_doc_package(CheckerInfo *info, AstPackage *pkg) { } array_add(&entities, e); } - gb_sort_array(entities.data, entities.count, cmp_entities_for_printing); + array_sort(entities, cmp_entities_for_printing); bool show_docs = (build_context.cmd_doc_flags & CmdDocFlag_Short) == 0; @@ -358,7 +358,7 @@ gb_internal void generate_documentation(Checker *c) { } } - gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name); + array_sort(pkgs, cmp_ast_package_by_name); for_array(i, pkgs) { print_doc_package(info, pkgs[i]); diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 1bc244918..26d8027a9 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -1107,7 +1107,7 @@ gb_internal void odin_doc_write_docs(OdinDocWriter *w) { } debugf("odin_doc_update_entities sort pkgs %s\n", w->state ? "preparing" : "writing"); - gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name); + array_sort(pkgs, cmp_ast_package_by_name); for_array(i, pkgs) { gbAllocator allocator = heap_allocator(); diff --git a/src/error.cpp b/src/error.cpp index e63682829..e5803e5a2 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -1,3 +1,14 @@ +enum ErrorValueKind : u32 { + ErrorValue_Error, + ErrorValue_Warning, +}; + +struct ErrorValue { + ErrorValueKind kind; + TokenPos pos; + Array msgs; +}; + struct ErrorCollector { TokenPos prev; std::atomic count; @@ -8,21 +19,54 @@ struct ErrorCollector { BlockingMutex string_mutex; RecursiveMutex block_mutex; - RecursiveMutex error_buffer_mutex; - Array error_buffer; - Array errors; + Array error_values; + ErrorValue curr_error_value; + std::atomic curr_error_value_set; }; gb_global ErrorCollector global_error_collector; +gb_internal void push_error_value(TokenPos const &pos, ErrorValueKind kind = ErrorValue_Error) { + GB_ASSERT(global_error_collector.curr_error_value_set.load() == false); + ErrorValue ev = {kind, pos}; + ev.msgs.allocator = heap_allocator(); + + global_error_collector.curr_error_value = ev; + global_error_collector.curr_error_value_set.store(true); +} + +gb_internal void pop_error_value(void) { + if (global_error_collector.curr_error_value_set.load()) { + array_add(&global_error_collector.error_values, global_error_collector.curr_error_value); + + global_error_collector.curr_error_value = {}; + global_error_collector.curr_error_value_set.store(false); + } +} + + +gb_internal void try_pop_error_value(void) { + if (!global_error_collector.in_block.load()) { + pop_error_value(); + } +} + +gb_internal ErrorValue *get_error_value(void) { + GB_ASSERT(global_error_collector.curr_error_value_set.load() == true); + return &global_error_collector.curr_error_value; +} + + + gb_internal bool any_errors(void) { return global_error_collector.count.load() != 0; } + + gb_internal void init_global_error_collector(void) { - array_init(&global_error_collector.errors, heap_allocator()); - array_init(&global_error_collector.error_buffer, heap_allocator()); + array_init(&global_error_collector.error_values, heap_allocator()); array_init(&global_file_path_strings, heap_allocator(), 1, 4096); array_init(&global_files, heap_allocator(), 1, 4096); } @@ -102,6 +146,7 @@ gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) { gb_internal bool global_warnings_as_errors(void); gb_internal bool global_ignore_warnings(void); gb_internal bool show_error_line(void); +gb_internal bool terse_errors(void); gb_internal bool has_ansi_terminal_colours(void); gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset); @@ -113,55 +158,32 @@ gb_internal void syntax_error(Token const &token, char const *fmt, ...); gb_internal void syntax_error(TokenPos pos, char const *fmt, ...); gb_internal void syntax_warning(Token const &token, char const *fmt, ...); gb_internal void compiler_error(char const *fmt, ...); +gb_internal void print_all_errors(void); -gb_internal void begin_error_block(void) { - mutex_lock(&global_error_collector.block_mutex); - global_error_collector.in_block.store(true); -} -gb_internal void end_error_block(void) { - mutex_lock(&global_error_collector.error_buffer_mutex); - isize n = global_error_collector.error_buffer.count; - if (n > 0) { - u8 *text = global_error_collector.error_buffer.data; - - bool add_extra_newline = false; +#define ERROR_OUT_PROC(name) void name(char const *fmt, va_list va) +typedef ERROR_OUT_PROC(ErrorOutProc); - if (show_error_line()) { - if (n >= 2 && !(text[n-2] == '\n' && text[n-1] == '\n')) { - add_extra_newline = true; - } - } else { - isize newline_count = 0; - for (isize i = 0; i < n; i++) { - if (text[i] == '\n') { - newline_count += 1; - } - } - if (newline_count > 1) { - add_extra_newline = true; - } - } +gb_internal ERROR_OUT_PROC(default_error_out_va) { + char buf[4096] = {}; + isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va); + isize n = len-1; - if (add_extra_newline) { - // add an extra new line as padding when the error line is being shown - error_line("\n"); - } + String msg = {(u8 *)buf, n}; - n = global_error_collector.error_buffer.count; - text = gb_alloc_array(permanent_allocator(), u8, n+1); - gb_memmove(text, global_error_collector.error_buffer.data, n); - text[n] = 0; + ErrorValue *ev = get_error_value(); + array_add(&ev->msgs, copy_string(permanent_allocator(), msg)); +} +gb_global ErrorOutProc *error_out_va = default_error_out_va; - mutex_lock(&global_error_collector.error_out_mutex); - String s = {text, n}; - array_add(&global_error_collector.errors, s); - mutex_unlock(&global_error_collector.error_out_mutex); +gb_internal void begin_error_block(void) { + mutex_lock(&global_error_collector.block_mutex); + global_error_collector.in_block.store(true); +} - global_error_collector.error_buffer.count = 0; - } - mutex_unlock(&global_error_collector.error_buffer_mutex); +gb_internal void end_error_block(void) { + pop_error_value(); global_error_collector.in_block.store(false); mutex_unlock(&global_error_collector.block_mutex); } @@ -169,40 +191,6 @@ gb_internal void end_error_block(void) { #define ERROR_BLOCK() begin_error_block(); defer (end_error_block()) -#define ERROR_OUT_PROC(name) void name(char const *fmt, va_list va) -typedef ERROR_OUT_PROC(ErrorOutProc); - -gb_internal ERROR_OUT_PROC(default_error_out_va) { - gbFile *f = gb_file_get_standard(gbFileStandard_Error); - - char buf[4096] = {}; - isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va); - isize n = len-1; - if (global_error_collector.in_block) { - mutex_lock(&global_error_collector.error_buffer_mutex); - - isize cap = global_error_collector.error_buffer.count + n; - array_reserve(&global_error_collector.error_buffer, cap); - u8 *data = global_error_collector.error_buffer.data + global_error_collector.error_buffer.count; - gb_memmove(data, buf, n); - global_error_collector.error_buffer.count += n; - - mutex_unlock(&global_error_collector.error_buffer_mutex); - } else { - mutex_lock(&global_error_collector.error_out_mutex); - { - u8 *text = gb_alloc_array(permanent_allocator(), u8, n+1); - gb_memmove(text, buf, n); - text[n] = 0; - array_add(&global_error_collector.errors, make_string(text, n)); - } - mutex_unlock(&global_error_collector.error_out_mutex); - - } - gb_file_write(f, buf, n); -} - -gb_global ErrorOutProc *error_out_va = default_error_out_va; gb_internal void error_out(char const *fmt, ...) { va_list va; @@ -357,9 +345,12 @@ gb_internal void error_out_coloured(char const *str, TerminalStyle style, Termin gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { global_error_collector.count.fetch_add(1); if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) { + print_all_errors(); gb_exit(1); } mutex_lock(&global_error_collector.mutex); + + push_error_value(pos, ErrorValue_Error); // NOTE(bill): Duplicate error, skip it if (pos.line == 0) { error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red); @@ -377,6 +368,7 @@ gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va } else { global_error_collector.count.fetch_sub(1); } + try_pop_error_value(); mutex_unlock(&global_error_collector.mutex); } @@ -387,6 +379,9 @@ gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, } global_error_collector.warning_count.fetch_add(1); mutex_lock(&global_error_collector.mutex); + + push_error_value(pos, ErrorValue_Warning); + if (!global_ignore_warnings()) { // NOTE(bill): Duplicate error, skip it if (pos.line == 0) { @@ -402,6 +397,7 @@ gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, show_error_on_line(pos, end); } } + try_pop_error_value(); mutex_unlock(&global_error_collector.mutex); } @@ -413,9 +409,13 @@ gb_internal void error_line_va(char const *fmt, va_list va) { gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) { global_error_collector.count.fetch_add(1); if (global_error_collector.count.load() > MAX_ERROR_COLLECTOR_COUNT()) { + print_all_errors(); gb_exit(1); } mutex_lock(&global_error_collector.mutex); + + push_error_value(pos, ErrorValue_Error); + // NOTE(bill): Duplicate error, skip it if (pos.line == 0) { error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red); @@ -428,6 +428,8 @@ gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_li } error_out_va(fmt, va); } + + try_pop_error_value(); mutex_unlock(&global_error_collector.mutex); } @@ -435,9 +437,13 @@ gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_li gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { global_error_collector.count.fetch_add(1); if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) { + print_all_errors(); gb_exit(1); } mutex_lock(&global_error_collector.mutex); + + push_error_value(pos, ErrorValue_Warning); + // NOTE(bill): Duplicate error, skip it if (global_error_collector.prev != pos) { global_error_collector.prev = pos; @@ -451,15 +457,21 @@ gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const * error_out_va(fmt, va); error_out("\n"); } + + try_pop_error_value(); mutex_unlock(&global_error_collector.mutex); } gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { global_error_collector.count.fetch_add(1); if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) { + print_all_errors(); gb_exit(1); } mutex_lock(&global_error_collector.mutex); + + push_error_value(pos, ErrorValue_Warning); + // NOTE(bill): Duplicate error, skip it if (pos.line == 0) { error_out_coloured("Syntax_Error: ", TerminalStyle_Normal, TerminalColour_Red); @@ -475,6 +487,8 @@ gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end, error_out("\n"); show_error_on_line(pos, end); } + + try_pop_error_value(); mutex_unlock(&global_error_collector.mutex); } @@ -486,6 +500,10 @@ gb_internal void syntax_warning_va(TokenPos const &pos, TokenPos end, char const } mutex_lock(&global_error_collector.mutex); global_error_collector.warning_count++; + + + push_error_value(pos, ErrorValue_Warning); + if (!global_ignore_warnings()) { // NOTE(bill): Duplicate error, skip it if (global_error_collector.prev != pos) { @@ -501,6 +519,8 @@ gb_internal void syntax_warning_va(TokenPos const &pos, TokenPos end, char const error_out("\n"); } } + + try_pop_error_value(); mutex_unlock(&global_error_collector.mutex); } @@ -568,6 +588,8 @@ gb_internal void syntax_error_with_verbose(TokenPos pos, TokenPos end, char cons gb_internal void compiler_error(char const *fmt, ...) { + print_all_errors(); + va_list va; va_start(va, fmt); @@ -577,3 +599,34 @@ gb_internal void compiler_error(char const *fmt, ...) { GB_DEBUG_TRAP(); gb_exit(1); } + + + + + +gb_internal int error_value_cmp(void const *a, void const *b) { + ErrorValue *x = cast(ErrorValue *)a; + ErrorValue *y = cast(ErrorValue *)b; + return token_pos_cmp(x->pos, y->pos); +} + +gb_internal void print_all_errors(void) { + GB_ASSERT(any_errors()); + gbFile *f = gb_file_get_standard(gbFileStandard_Error); + + array_sort(global_error_collector.error_values, error_value_cmp); + + for_array(i, global_error_collector.error_values) { + ErrorValue ev = global_error_collector.error_values[i]; + for_array(j, ev.msgs) { + String msg = ev.msgs[j]; + gb_file_write(f, msg.text, msg.len); + if (terse_errors()) { + if (string_contains_char(msg, '\n')) { + break; + } + } + } + } + +} \ No newline at end of file diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index ca4341525..b8ee7e7fa 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3021,7 +3021,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } } - gb_sort_array(gen->foreign_libraries.data, gen->foreign_libraries.count, foreign_library_cmp); + array_sort(gen->foreign_libraries, foreign_library_cmp); return true; } diff --git a/src/main.cpp b/src/main.cpp index 7951ca2db..0f28e137f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2095,7 +2095,7 @@ gb_internal void print_show_unused(Checker *c) { array_add(&unused, e); } - gb_sort_array(unused.data, unused.count, cmp_entities_for_printing); + array_sort(unused, cmp_entities_for_printing); print_usage_line(0, "Unused Package Declarations"); @@ -2680,6 +2680,7 @@ int main(int arg_count, char const **arg_ptr) { } if (any_errors()) { + print_all_errors(); return 1; } @@ -2691,6 +2692,7 @@ int main(int arg_count, char const **arg_ptr) { check_parsed_files(checker); if (any_errors()) { + print_all_errors(); return 1; } diff --git a/src/string.cpp b/src/string.cpp index 8be40ec3c..7bfa52f33 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -89,7 +89,6 @@ gb_internal char *alloc_cstring(gbAllocator a, String s) { } - gb_internal gb_inline bool str_eq_ignore_case(String const &a, String const &b) { if (a.len == b.len) { for (isize i = 0; i < a.len; i++) { -- cgit v1.2.3 From 18fb665bf684b6f55cc513eddd14e3224f9e70ad Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 19 Mar 2024 21:15:47 +0000 Subject: Correct matrix builtins for `#row_major` --- src/check_builtin.cpp | 4 ++-- src/check_expr.cpp | 11 +++++++++-- src/types.cpp | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 6de3b27f2..d3158961e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3488,7 +3488,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } } else { GB_ASSERT(t->kind == Type_Matrix); - operand->type = alloc_type_matrix(t->Matrix.elem, t->Matrix.column_count, t->Matrix.row_count); + operand->type = alloc_type_matrix(t->Matrix.elem, t->Matrix.column_count, t->Matrix.row_count, nullptr, nullptr, t->Matrix.is_row_major); } operand->type = check_matrix_type_hint(operand->type, type_hint); break; @@ -3556,7 +3556,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } operand->mode = Addressing_Value; - operand->type = alloc_type_matrix(elem, xt->Array.count, yt->Array.count); + operand->type = alloc_type_matrix(elem, xt->Array.count, yt->Array.count, nullptr, nullptr, false); operand->type = check_matrix_type_hint(operand->type, type_hint); break; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 67c7f1a04..e9a6f5122 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3397,6 +3397,13 @@ gb_internal Type *check_matrix_type_hint(Type *matrix, Type *type_hint) { Type *th = base_type(type_hint); if (are_types_identical(th, xt)) { return type_hint; + } else if (xt->kind == Type_Matrix && th->kind == Type_Matrix) { + if (!are_types_identical(xt->Matrix.elem, th->Matrix.elem)) { + // ignore + } if (xt->Matrix.row_count == th->Matrix.row_count && + xt->Matrix.column_count == th->Matrix.column_count) { + return type_hint; + } } else if (xt->kind == Type_Matrix && th->kind == Type_Array) { if (!are_types_identical(xt->Matrix.elem, th->Array.elem)) { // ignore @@ -3461,7 +3468,7 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand if (xt->Matrix.row_count == yt->Array.count) { x->type = y->type; } else { - x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, 1); + x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, 1, nullptr, nullptr, xt->Matrix.is_row_major); } goto matrix_success; } @@ -3492,7 +3499,7 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand if (yt->Matrix.column_count == xt->Array.count) { x->type = x->type; } else { - x->type = alloc_type_matrix(yt->Matrix.elem, 1, yt->Matrix.column_count); + x->type = alloc_type_matrix(yt->Matrix.elem, 1, yt->Matrix.column_count, nullptr, nullptr, yt->Matrix.is_row_major); } goto matrix_success; } else if (are_types_identical(yt->Matrix.elem, xt)) { diff --git a/src/types.cpp b/src/types.cpp index ab5e4de03..c2358056b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1003,7 +1003,7 @@ gb_internal Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = return t; } -gb_internal Type *alloc_type_matrix(Type *elem, i64 row_count, i64 column_count, Type *generic_row_count = nullptr, Type *generic_column_count = nullptr, bool is_row_major = false) { +gb_internal Type *alloc_type_matrix(Type *elem, i64 row_count, i64 column_count, Type *generic_row_count, Type *generic_column_count, bool is_row_major) { if (generic_row_count != nullptr || generic_column_count != nullptr) { Type *t = alloc_type(Type_Matrix); t->Matrix.elem = elem; -- cgit v1.2.3 From 517d7ae0b0fd400ceb6a213e7d644c19b8088bfd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 23 Mar 2024 17:51:56 +0000 Subject: Add error block around `error_line` calls --- src/check_builtin.cpp | 3 +++ src/check_decl.cpp | 1 + src/check_expr.cpp | 5 +++++ src/check_stmt.cpp | 5 +++++ src/checker.cpp | 12 +++++++++++- src/parser.cpp | 6 +++--- 6 files changed, 28 insertions(+), 4 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index d3158961e..53e4acbd1 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -89,6 +89,7 @@ gb_internal void check_or_else_split_types(CheckerContext *c, Operand *x, String gb_internal void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) { + ERROR_BLOCK(); gbString t = type_to_string(x.type); error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t); if (is_type_union(type_deref(x.type))) { @@ -1565,6 +1566,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o } if (!operand->value.value_bool) { + ERROR_BLOCK(); gbString arg1 = expr_to_string(ce->args[0]); gbString arg2 = {}; @@ -1590,6 +1592,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o operand->type = t_untyped_bool; operand->mode = Addressing_Constant; } else if (name == "panic") { + ERROR_BLOCK(); if (ce->args.count != 1) { error(call, "'#panic' expects 1 argument, got %td", ce->args.count); return false; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 2c0f7a7b8..952a877a4 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1630,6 +1630,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de Entity *uvar = entry.uvar; Entity *prev = scope_insert_no_mutex(ctx->scope, uvar); if (prev != nullptr) { + ERROR_BLOCK(); error(e->token, "Namespace collision while 'using' procedure argument '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string)); error_line("%.*s != %.*s\n", LIT(uvar->token.string), LIT(prev->token.string)); break; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 80008d73a..ecc8a804c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5905,6 +5905,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A s = assign_score_function(MAXIMUM_TYPE_DISTANCE); } else { if (show_error) { + ERROR_BLOCK(); check_assignment(c, o, param_type, str_lit("procedure argument")); Type *src = base_type(o->type); @@ -8459,6 +8460,7 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no // NOTE(bill): allow implicit conversion between boolean types // within 'or_return' to improve the experience using third-party code } else if (!check_is_assignable_to(c, &rhs, end_type)) { + ERROR_BLOCK(); // TODO(bill): better error message gbString a = type_to_string(right_type); gbString b = type_to_string(end_type); @@ -10030,6 +10032,7 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, bool ok = check_index_value(c, t, false, ie->index, max_count, &index, index_type_hint); if (is_const) { if (index < 0) { + ERROR_BLOCK(); gbString str = expr_to_string(o->expr); error(o->expr, "Cannot index a constant '%s'", str); if (!build_context.terse_errors) { @@ -10046,6 +10049,7 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, bool finish = false; o->value = get_constant_field_single(c, value, cast(i32)index, &success, &finish); if (!success) { + ERROR_BLOCK(); gbString str = expr_to_string(o->expr); error(o->expr, "Cannot index a constant '%s' with index %lld", str, cast(long long)index); if (!build_context.terse_errors) { @@ -10236,6 +10240,7 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, } } if (!all_constant) { + ERROR_BLOCK(); gbString str = expr_to_string(o->expr); error(o->expr, "Cannot slice '%s' with non-constant indices", str); if (!build_context.terse_errors) { diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index d34695a3a..1d7e7d4e9 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -883,6 +883,7 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod } if (ctx->inline_for_depth >= MAX_INLINE_FOR_DEPTH && prev_inline_for_depth < MAX_INLINE_FOR_DEPTH) { + ERROR_BLOCK(); if (prev_inline_for_depth > 0) { error(node, "Nested '#unroll for' loop cannot be inlined as it exceeds the maximum '#unroll for' depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH); } else { @@ -1592,6 +1593,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { isize count = t->Tuple.variables.count; if (count < 1 || count > 3) { + ERROR_BLOCK(); check_not_tuple(ctx, &operand); error_line("\tMultiple return valued parameters in a range statement are limited to a maximum of 2 usable values with a trailing boolean for the conditional\n"); break; @@ -2085,6 +2087,9 @@ gb_internal void check_expr_stmt(CheckerContext *ctx, Ast *node) { } return; } + + ERROR_BLOCK(); + gbString expr_str = expr_to_string(operand.expr); error(node, "Expression is not used: '%s'", expr_str); gb_string_free(expr_str); diff --git a/src/checker.cpp b/src/checker.cpp index bf6a84588..6456cab0c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3180,6 +3180,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { linkage == "link_once") { ac->linkage = linkage; } else { + ERROR_BLOCK(); error(elem, "Invalid linkage '%.*s'. Valid kinds:", LIT(linkage)); error_line("\tinternal\n"); error_line("\tstrong\n"); @@ -3428,6 +3429,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } else if (mode == "speed") { ac->optimization_mode = ProcedureOptimizationMode_Speed; } else { + ERROR_BLOCK(); error(elem, "Invalid optimization_mode for '%.*s'. Valid modes:", LIT(name)); error_line("\tnone\n"); error_line("\tminimal\n"); @@ -3558,6 +3560,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) { model == "localexec") { ac->thread_local_model = model; } else { + ERROR_BLOCK(); error(elem, "Invalid thread local model '%.*s'. Valid models:", LIT(model)); error_line("\tdefault\n"); error_line("\tlocaldynamic\n"); @@ -3608,6 +3611,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) { linkage == "link_once") { ac->linkage = linkage; } else { + ERROR_BLOCK(); error(elem, "Invalid linkage '%.*s'. Valid kinds:", LIT(linkage)); error_line("\tinternal\n"); error_line("\tstrong\n"); @@ -3762,6 +3766,7 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array const &at if (!proc(c, elem, name, value, ac)) { if (!build_context.ignore_unknown_attributes) { + ERROR_BLOCK(); error(elem, "Unknown attribute element name '%.*s'", LIT(name)); error_line("\tDid you forget to use build flag '-ignore-unknown-attributes'?\n"); } @@ -3831,6 +3836,8 @@ gb_internal bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_ gb_string_free(str); return false; } else if (is_global) { + ERROR_BLOCK(); + Ast *n = vd->values[rhs-1]; error(n, "Expected %td expressions on the right hand side, got %td", lhs, rhs); error_line("Note: Global declarations do not allow for multi-valued expressions"); @@ -6052,11 +6059,14 @@ gb_internal void check_unique_package_names(Checker *c) { continue; } + + begin_error_block(); error(curr, "Duplicate declaration of 'package %.*s'", LIT(name)); error_line("\tA package name must be unique\n" "\tThere is no relation between a package name and the directory that contains it, so they can be completely different\n" "\tA package name is required for link name prefixing to have a consistent ABI\n"); - error(prev, "found at previous location"); + error_line("%s found at previous location\n", token_pos_to_string(ast_token(prev).pos)); + end_error_block(); } } diff --git a/src/parser.cpp b/src/parser.cpp index bb9a526fe..b4a2e060c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6295,7 +6295,7 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) { if (!path_is_directory(init_fullpath)) { String const ext = str_lit(".odin"); if (!string_ends_with(init_fullpath, ext)) { - error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename)); + error({}, "Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename)); return ParseFile_WrongExtension; } } else if (init_fullpath.len != 0) { @@ -6308,7 +6308,7 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) { String short_path = filename_from_path(path); char *cpath = alloc_cstring(temporary_allocator(), short_path); if (gb_file_exists(cpath)) { - error_line("Please specify the executable name with -out: as a directory exists with the same name in the current working directory"); + error({}, "Please specify the executable name with -out: as a directory exists with the same name in the current working directory"); return ParseFile_DirectoryAlreadyExists; } } @@ -6344,7 +6344,7 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) { if (!path_is_directory(fullpath)) { String const ext = str_lit(".odin"); if (!string_ends_with(fullpath, ext)) { - error_line("Expected either a directory or a .odin file, got '%.*s'\n", LIT(fullpath)); + error({}, "Expected either a directory or a .odin file, got '%.*s'\n", LIT(fullpath)); return ParseFile_WrongExtension; } } -- cgit v1.2.3 From 6d4f30de1a85fe51159808d70a342c1c915d15de Mon Sep 17 00:00:00 2001 From: rick-masters Date: Sun, 24 Mar 2024 16:28:55 +0000 Subject: Fix fields_wait_signal futex. --- src/check_builtin.cpp | 2 ++ src/check_expr.cpp | 1 + src/check_type.cpp | 4 ++++ src/threading.cpp | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 53e4acbd1..f4aa9567d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3393,6 +3393,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As elem->Struct.tags = gb_alloc_array(permanent_allocator(), String, fields.count); elem->Struct.node = dummy_node_struct; type_set_offsets(elem); + wait_signal_set(&elem->Struct.fields_wait_signal); } Type *soa_type = make_soa_struct_slice(c, dummy_node_soa, nullptr, elem); @@ -3766,6 +3767,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As soa_struct->Struct.tags[i] = old_struct->Struct.tags[i]; } } + wait_signal_set(&soa_struct->Struct.fields_wait_signal); Token token = {}; token.string = str_lit("Base_Type"); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fd10374c1..d19af4a62 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8873,6 +8873,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * break; } + wait_signal_until_available(&t->Struct.fields_wait_signal); isize field_count = t->Struct.fields.count; isize min_field_count = t->Struct.fields.count; for (isize i = min_field_count-1; i >= 0; i--) { diff --git a/src/check_type.cpp b/src/check_type.cpp index 0b9042905..ae79d4edc 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2490,6 +2490,7 @@ gb_internal Type *get_map_cell_type(Type *type) { s->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("v"), alloc_type_array(type, len), false, 0, EntityState_Resolved); s->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("_"), alloc_type_array(t_u8, padding), false, 1, EntityState_Resolved); s->Struct.scope = scope; + wait_signal_set(&s->Struct.fields_wait_signal); gb_unused(type_size_of(s)); return s; @@ -2520,6 +2521,7 @@ gb_internal void init_map_internal_types(Type *type) { metadata_type->Struct.fields[4] = alloc_entity_field(metadata_scope, make_token_ident("value_cell"), value_cell, false, 4, EntityState_Resolved); metadata_type->Struct.scope = metadata_scope; metadata_type->Struct.node = nullptr; + wait_signal_set(&metadata_type->Struct.fields_wait_signal); gb_unused(type_size_of(metadata_type)); @@ -2537,6 +2539,7 @@ gb_internal void init_map_internal_types(Type *type) { debug_type->Struct.fields[3] = alloc_entity_field(scope, make_token_ident("__metadata"), metadata_type, false, 3, EntityState_Resolved); debug_type->Struct.scope = scope; debug_type->Struct.node = nullptr; + wait_signal_set(&debug_type->Struct.fields_wait_signal); gb_unused(type_size_of(debug_type)); @@ -2832,6 +2835,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e add_entity(ctx, scope, nullptr, base_type_entity); add_type_info_type(ctx, soa_struct); + wait_signal_set(&soa_struct->Struct.fields_wait_signal); return soa_struct; } diff --git a/src/threading.cpp b/src/threading.cpp index a469435d2..9e4a1607c 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -113,7 +113,7 @@ struct Wait_Signal { gb_internal void wait_signal_until_available(Wait_Signal *ws) { if (ws->futex.load() == 0) { - futex_wait(&ws->futex, 1); + futex_wait(&ws->futex, 0); } } -- cgit v1.2.3 From ce196529dcb62a1955ca1156090c444947e92fa6 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Mon, 8 Apr 2024 13:55:23 +0200 Subject: enable the required target feature `atomics` when using them in wasm --- base/intrinsics/intrinsics.odin | 2 ++ src/check_builtin.cpp | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 78f4f3f41..458596adf 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -293,7 +293,9 @@ wasm_memory_size :: proc(index: uintptr) -> int --- // 0 - indicates that the thread blocked and then was woken up // 1 - the loaded value from `ptr` did not match `expected`, the thread did not block // 2 - the thread blocked, but the timeout +@(enable_target_feature="atomics") wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) -> u32 --- +@(enable_target_feature="atomics") wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) --- // x86 Targets (i386, amd64) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index f4aa9567d..d8fad487b 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -6014,6 +6014,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } + enable_target_feature({}, str_lit("atomics")); + Operand ptr = {}; Operand expected = {}; Operand timeout = {}; @@ -6066,6 +6068,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } + enable_target_feature({}, str_lit("atomics")); + Operand ptr = {}; Operand waiters = {}; check_expr(c, &ptr, ce->args[0]); if (ptr.mode == Addressing_Invalid) return false; -- cgit v1.2.3 From 3dfd61dd4f1aec7525a8d6820c9c977f6a3ed14e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 10 Apr 2024 12:32:26 +0100 Subject: Make `intrinsics.overflow_*` NOT `#optional_ok` --- src/check_builtin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index d8fad487b..c3c217ec7 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4089,8 +4089,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } } - operand->mode = Addressing_OptionalOk; - operand->type = default_type(x.type); + operand->mode = Addressing_Value; + operand->type = make_optional_ok_type(default_type(x.type)); } break; -- cgit v1.2.3 From 25f1d0906d2b5a8276c3832783970a798c12cc6c Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 1 May 2024 22:12:37 +0200 Subject: compiler: improve target features support --- .gitignore | 4 +- base/intrinsics/intrinsics.odin | 10 +- core/simd/x86/sse3.odin | 4 +- core/simd/x86/sse41.odin | 4 +- core/sync/futex_wasm.odin | 44 ++- misc/featuregen/README.md | 28 ++ misc/featuregen/featuregen.cpp | 37 +++ misc/featuregen/featuregen.py | 116 ++++++++ src/build_settings.cpp | 617 ++++++++++++++++++++++++++++++++++------ src/check_builtin.cpp | 46 ++- src/check_decl.cpp | 49 +++- src/check_expr.cpp | 68 ++++- src/checker_builtin_procs.hpp | 4 + src/entity.cpp | 4 +- src/llvm_backend.cpp | 104 +++---- src/llvm_backend_proc.cpp | 27 +- src/llvm_backend_utility.cpp | 3 +- src/main.cpp | 79 ++++- src/types.cpp | 22 ++ 19 files changed, 1066 insertions(+), 204 deletions(-) create mode 100644 misc/featuregen/README.md create mode 100644 misc/featuregen/featuregen.cpp create mode 100644 misc/featuregen/featuregen.py (limited to 'src/check_builtin.cpp') diff --git a/.gitignore b/.gitignore index f6c3927a2..2b6b5281a 100644 --- a/.gitignore +++ b/.gitignore @@ -322,4 +322,6 @@ build.sh !core/debug/ # RAD debugger project file -*.raddbg \ No newline at end of file +*.raddbg + +misc/featuregen/featuregen diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index dca33bfd9..d887f8dcc 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -282,6 +282,12 @@ simd_reverse :: proc(a: #simd[N]T) -> #simd[N]T --- simd_rotate_left :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T --- simd_rotate_right :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T --- +// Checks if the current target supports the given target features. +// +// Takes a constant comma-seperated string (eg: "sha512,sse4.1"), or a procedure type which has either +// `@(require_target_feature)` or `@(enable_target_feature)` as its input and returns a boolean indicating +// if all listed features are supported. +has_target_feature :: proc($test: $T) -> bool where type_is_string(T) || type_is_proc(T) --- // WASM targets only wasm_memory_grow :: proc(index, delta: uintptr) -> int --- @@ -293,9 +299,9 @@ wasm_memory_size :: proc(index: uintptr) -> int --- // 0 - indicates that the thread blocked and then was woken up // 1 - the loaded value from `ptr` did not match `expected`, the thread did not block // 2 - the thread blocked, but the timeout -@(enable_target_feature="atomics") +@(require_target_feature="atomics") wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) -> u32 --- -@(enable_target_feature="atomics") +@(require_target_feature="atomics") wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) --- // x86 Targets (i386, amd64) diff --git a/core/simd/x86/sse3.odin b/core/simd/x86/sse3.odin index cf5f3b2fa..ca19c3954 100644 --- a/core/simd/x86/sse3.odin +++ b/core/simd/x86/sse3.odin @@ -36,7 +36,7 @@ _mm_lddqu_si128 :: #force_inline proc "c" (mem_addr: ^__m128i) -> __m128i { _mm_movedup_pd :: #force_inline proc "c" (a: __m128d) -> __m128d { return simd.shuffle(a, a, 0, 0) } -@(require_results, enable_target_feature="sse3") +@(require_results, enable_target_feature="sse2,sse3") _mm_loaddup_pd :: #force_inline proc "c" (mem_addr: [^]f64) -> __m128d { return _mm_load1_pd(mem_addr) } @@ -65,4 +65,4 @@ foreign _ { hsubps :: proc(a, b: __m128) -> __m128 --- @(link_name = "llvm.x86.sse3.ldu.dq") lddqu :: proc(mem_addr: rawptr) -> i8x16 --- -} \ No newline at end of file +} diff --git a/core/simd/x86/sse41.odin b/core/simd/x86/sse41.odin index 8c306ba4c..0b9c5986f 100644 --- a/core/simd/x86/sse41.odin +++ b/core/simd/x86/sse41.odin @@ -268,7 +268,7 @@ _mm_testnzc_si128 :: #force_inline proc "c" (a: __m128i, mask: __m128i) -> i32 { _mm_test_all_zeros :: #force_inline proc "c" (a: __m128i, mask: __m128i) -> i32 { return _mm_testz_si128(a, mask) } -@(require_results, enable_target_feature="sse4.1") +@(require_results, enable_target_feature="sse2,sse4.1") _mm_test_all_ones :: #force_inline proc "c" (a: __m128i) -> i32 { return _mm_testc_si128(a, _mm_cmpeq_epi32(a, a)) } @@ -349,4 +349,4 @@ foreign _ { ptestc :: proc(a, mask: i64x2) -> i32 --- @(link_name = "llvm.x86.sse41.ptestnzc") ptestnzc :: proc(a, mask: i64x2) -> i32 --- -} \ No newline at end of file +} diff --git a/core/sync/futex_wasm.odin b/core/sync/futex_wasm.odin index de1013364..de88e8198 100644 --- a/core/sync/futex_wasm.odin +++ b/core/sync/futex_wasm.odin @@ -5,31 +5,49 @@ package sync import "base:intrinsics" import "core:time" +// NOTE: because `core:sync` is in the dependency chain of a lot of the core packages (mostly through `core:mem`) +// without actually calling into it much, I opted for a runtime panic instead of a compile error here. + _futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool { - s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1) - return s != 0 + when !intrinsics.has_target_feature("atomics") { + _panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it") + } else { + s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1) + return s != 0 + } } _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool { - s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration)) - return s != 0 - + when !intrinsics.has_target_feature("atomics") { + _panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it") + } else { + s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration)) + return s != 0 + } } _futex_signal :: proc "contextless" (f: ^Futex) { - loop: for { - s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1) - if s >= 1 { - return + when !intrinsics.has_target_feature("atomics") { + _panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it") + } else { + loop: for { + s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1) + if s >= 1 { + return + } } } } _futex_broadcast :: proc "contextless" (f: ^Futex) { - loop: for { - s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0)) - if s >= 0 { - return + when !intrinsics.has_target_feature("atomics") { + _panic("usage of `core:sync` requires the `-target-feature:\"atomics\"` or a `-microarch` that supports it") + } else { + loop: for { + s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0)) + if s >= 0 { + return + } } } } diff --git a/misc/featuregen/README.md b/misc/featuregen/README.md new file mode 100644 index 000000000..22a798cca --- /dev/null +++ b/misc/featuregen/README.md @@ -0,0 +1,28 @@ +# Featuregen + +This directory contains a python and CPP script that generates the needed information +for features regarding microarchitecture and target features of the compiler. + +It is not pretty! But LLVM has no way to query this information with their C API. + +It generates these globals (intended for `src/build_settings.cpp`: + +- `target_microarch_list`: an array of strings indexed by the architecture, each string is a comma-seperated list of microarchitectures available on that architecture +- `target_features_list`: an array of strings indexed by the architecture, each string is a comma-seperated list of target features available on that architecture +- `target_microarch_counts`: an array of ints indexed by the architecture, each int represents the amount of microarchitectures available on that target, intended for easier iteration of the next global +- `microarch_features_list`: an array of a tuple like struct where the first string is a microarchitecture and the second is a comma-seperated list of all features that are enabled by default for it + +In order to get the default features for a microarchitecture there is a small CPP program that takes +a target triple and microarchitecture and spits out the default features, this is then parsed by the python script. + +This should be ran each time we update LLVM to stay in sync. + +If there are minor differences (like the Odin user using LLVM 14 and this table being generated on LLVM 17) it +does not impact much at all, the only thing it will do is make LLVM print a message that the feature is ignored (if it was added between 14 and 17 in this case). + +## Usage + +1. Make sure the table of architectures at the top of the python script is up-to-date (the triple can be any valid triple for the architecture) +1. `./build.sh` +1. `python3 featuregen.py` +1. Copy the output into `src/build_settings.cpp` diff --git a/misc/featuregen/featuregen.cpp b/misc/featuregen/featuregen.cpp new file mode 100644 index 000000000..a1d00ab31 --- /dev/null +++ b/misc/featuregen/featuregen.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +#include + +// Dumps the default set of supported features for the given microarch. +int main(int argc, char **argv) { + if (argc < 3) { + llvm::errs() << "Error: first arg should be triple, second should be microarch\n"; + return 1; + } + + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + + std::string error; + const llvm::Target* target = llvm::TargetRegistry::lookupTarget(argv[1], error); + + if (!target) { + llvm::errs() << "Error: " << error << "\n"; + return 1; + } + + auto STI = target->createMCSubtargetInfo(argv[1], argv[2], ""); + + std::string plus = "+"; + llvm::ArrayRef features = STI->getAllProcessorFeatures(); + for (const auto& feature : features) { + if (STI->checkFeatures(plus + feature.Key)) { + llvm::outs() << feature.Key << "\n"; + } + } + + return 0; +} diff --git a/misc/featuregen/featuregen.py b/misc/featuregen/featuregen.py new file mode 100644 index 000000000..da4cc68f5 --- /dev/null +++ b/misc/featuregen/featuregen.py @@ -0,0 +1,116 @@ +import subprocess +import tempfile +import os +import sys + +archs = [ + ("amd64", "linux_amd64", "x86_64-pc-linux-gnu", [], []), + ("i386", "linux_i386", "i386-pc-linux-gnu", [], []), + ("arm32", "linux_arm32", "arm-linux-gnu", [], []), + ("arm64", "linux_arm64", "aarch64-linux-elf", [], []), + ("wasm32", "js_wasm32", "wasm32-js-js", [], []), + ("wasm64p32", "js_wasm64p32","wasm32-js-js", [], []), +]; + +SEEKING_CPUS = 0 +PARSING_CPUS = 1 +PARSING_FEATURES = 2 + +with tempfile.NamedTemporaryFile(suffix=".odin", delete=True) as temp_file: + temp_file.write(b"package main\n") + + for arch, target, triple, cpus, features in archs: + cmd = ["odin", "build", temp_file.name, "-file", "-build-mode:llvm", "-out:temp", "-target-features:\"help\"", f"-target:\"{target}\""] + process = subprocess.Popen(cmd, stderr=subprocess.PIPE, text=True) + + state = SEEKING_CPUS + for line in process.stderr: + + if state == SEEKING_CPUS: + if line == "Available CPUs for this target:\n": + state = PARSING_CPUS + + elif state == PARSING_CPUS: + if line == "Available features for this target:\n": + state = PARSING_FEATURES + continue + + parts = line.split(" -", maxsplit=1) + if len(parts) < 2: + continue + + cpu = parts[0].strip() + cpus.append(cpu) + + elif state == PARSING_FEATURES: + if line == "\n" and len(features) > 0: + break + + parts = line.split(" -", maxsplit=1) + if len(parts) < 2: + continue + + feature = parts[0].strip() + features.append(feature) + + process.wait() + if process.returncode != 0: + print(f"odin build returned with non-zero exit code {process.returncode}") + sys.exit(1) + + os.remove("temp.ll") + +def print_default_features(triple, microarch): + cmd = ["./featuregen", triple, microarch] + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True) + first = True + for line in process.stdout: + print("" if first else ",", line.strip(), sep="", end="") + first = False + process.wait() + if process.returncode != 0: + print(f"featuregen returned with non-zero exit code {process.returncode}") + sys.exit(1) + +print("// Generated with the featuregen script in `misc/featuregen`") +print("gb_global String target_microarch_list[TargetArch_COUNT] = {") +print("\t// TargetArch_Invalid:") +print('\tstr_lit(""),') +for arch, target, triple, cpus, features in archs: + print(f"\t// TargetArch_{arch}:") + print(f'\tstr_lit("{','.join(cpus)}"),') +print("};") + +print("") + +print("// Generated with the featuregen script in `misc/featuregen`") +print("gb_global String target_features_list[TargetArch_COUNT] = {") +print("\t// TargetArch_Invalid:") +print('\tstr_lit(""),') +for arch, target, triple, cpus, features in archs: + print(f"\t// TargetArch_{arch}:") + print(f'\tstr_lit("{','.join(features)}"),') +print("};") + +print("") + +print("// Generated with the featuregen script in `misc/featuregen`") +print("gb_global int target_microarch_counts[TargetArch_COUNT] = {") +print("\t// TargetArch_Invalid:") +print("\t0,") +for arch, target, triple, cpus, feature in archs: + print(f"\t// TargetArch_{arch}:") + print(f"\t{len(cpus)},") +print("};") + +print("") + +print("// Generated with the featuregen script in `misc/featuregen`") +print("gb_global MicroarchFeatureList microarch_features_list[] = {") +for arch, target, triple, cpus, features in archs: + print(f"\t// TargetArch_{arch}:") + for cpu in cpus: + print(f'\t{{ str_lit("{cpu}"), str_lit("', end="") + print_default_features(triple, cpu) + print('") },') +print("};") diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 8509394ff..8ad03b1b9 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -71,6 +71,11 @@ enum Windows_Subsystem : u8 { Windows_Subsystem_COUNT, }; +struct MicroarchFeatureList { + String microarch; + String features; +}; + gb_global String target_os_names[TargetOs_COUNT] = { str_lit(""), str_lit("windows"), @@ -97,21 +102,467 @@ gb_global String target_arch_names[TargetArch_COUNT] = { str_lit("wasm64p32"), }; +// Generated with the featuregen script in `misc/featuregen` 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,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,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,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,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"), - // TargetArch_wasm64p32, - str_lit("generic"), + // TargetArch_Invalid: + str_lit(""), + // TargetArch_amd64: + str_lit("alderlake,amdfam10,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,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,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,penryn,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,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4"), + // TargetArch_i386: + str_lit("alderlake,amdfam10,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,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,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,penryn,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,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4"), + // 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,iwmmxt,krait,kryo,mpcore,mpcorenovfp,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,kryo,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), + // TargetArch_wasm32: + str_lit("bleeding-edge,generic,mvp"), + // TargetArch_wasm64p32: + str_lit("bleeding-edge,generic,mvp"), +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global String target_features_list[TargetArch_COUNT] = { + // TargetArch_Invalid: + str_lit(""), + // TargetArch_amd64: + str_lit("16bit-mode,32bit-mode,3dnow,3dnowa,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512er,avx512f,avx512fp16,avx512ifma,avx512pf,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branchfusion,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-gather,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prefetchwt1,prfchw,ptwrite,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves"), + // TargetArch_i386: + str_lit("16bit-mode,32bit-mode,3dnow,3dnowa,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512er,avx512f,avx512fp16,avx512ifma,avx512pf,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branchfusion,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-gather,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prefetchwt1,prfchw,ptwrite,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves"), + // TargetArch_arm32: + str_lit("32bit,8msecext,a12,a15,a17,a32,a35,a5,a53,a55,a57,a7,a72,a73,a75,a76,a77,a78c,a8,a9,aapcs-frame-chain,aapcs-frame-chain-leaf,aclass,acquire-release,aes,armv4,armv4t,armv5t,armv5te,armv5tej,armv6,armv6-m,armv6j,armv6k,armv6kz,armv6s-m,armv6t2,armv7-a,armv7-m,armv7-r,armv7e-m,armv7k,armv7s,armv7ve,armv8-a,armv8-m.base,armv8-m.main,armv8-r,armv8.1-a,armv8.1-m.main,armv8.2-a,armv8.3-a,armv8.4-a,armv8.5-a,armv8.6-a,armv8.7-a,armv8.8-a,armv8.9-a,armv9-a,armv9.1-a,armv9.2-a,armv9.3-a,armv9.4-a,atomics-32,avoid-movs-shop,avoid-partial-cpsr,bf16,big-endian-instructions,cde,cdecp0,cdecp1,cdecp2,cdecp3,cdecp4,cdecp5,cdecp6,cdecp7,cheap-predicable-cpsr,clrbhb,cortex-a710,cortex-a78,cortex-x1,cortex-x1c,crc,crypto,d32,db,dfb,disable-postra-scheduler,dont-widen-vmovs,dotprod,dsp,execute-only,expand-fp-mlx,exynos,fix-cmse-cve-2021-35465,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpao,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hwdiv,hwdiv-arm,i8mm,iwmmxt,iwmmxt2,krait,kryo,lob,long-calls,loop-align,m3,m7,mclass,mp,muxed-units,mve,mve.fp,mve1beat,mve2beat,mve4beat,nacl-trap,neon,neon-fpmovs,neonfp,neoverse-v1,no-branch-predictor,no-bti-at-return-twice,no-movt,no-neg-immediates,noarm,nonpipelined-vfp,pacbti,perfmon,prefer-ishst,prefer-vmovsr,prof-unpr,r4,r5,r52,r7,ras,rclass,read-tp-tpidrprw,read-tp-tpidruro,read-tp-tpidrurw,reserve-r9,ret-addr-stack,sb,sha2,slow-fp-brcc,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,soft-float,splat-vfp-neon,strict-align,swift,thumb-mode,thumb2,trustzone,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.1m.main,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8m,v8m.main,v9.1a,v9.2a,v9.3a,v9.4a,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align,vmlx-forwarding,vmlx-hazards,wide-stride-vfp,xscale,zcz"), + // TargetArch_arm64: + str_lit("CONTEXTIDREL2,a35,a510,a53,a55,a57,a64fx,a65,a710,a715,a72,a73,a75,a76,a77,a78,a78c,aes,aggressive-fma,all,alternate-sextload-cvt-f32-pattern,altnzcv,am,ampere1,ampere1a,amvs,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,ascend-store-address,b16b16,balance-fp-ops,bf16,brbe,bti,call-saved-x10,call-saved-x11,call-saved-x12,call-saved-x13,call-saved-x14,call-saved-x15,call-saved-x18,call-saved-x8,call-saved-x9,carmel,ccdp,ccidx,ccpp,chk,clrbhb,cmp-bcc-fusion,complxnum,cortex-r82,cortex-x1,cortex-x2,cortex-x3,crc,crypto,cssc,custom-cheap-as-move,d128,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,exynos-cheap-as-move,exynosm3,exynosm4,f32mm,f64mm,falkor,fgt,fix-cortex-a53-835769,flagm,fmv,force-32bit-jump-tables,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,gcs,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hbc,hcx,i8mm,ite,jsconv,kryo,lor,ls64,lse,lse128,lse2,lsl-fast,mec,mops,mpam,mte,neon,neoverse512tvb,neoversee1,neoversen1,neoversen2,neoversev1,neoversev2,nmi,no-bti-at-return-twice,no-neg-immediates,no-sve-fp-ld1r,no-zcz-fp,nv,outline-atomics,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,prfm-slc-target,rand,ras,rasv2,rcpc,rcpc-immo,rcpc3,rdm,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x18,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x3,reserve-x30,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x9,rme,saphira,sb,sel2,sha2,sha3,slow-misaligned-128store,slow-paired-128,slow-strqro-store,sm4,sme,sme-f16f16,sme-f64f64,sme-i16i64,sme2,sme2p1,spe,spe-eef,specres2,specrestrict,ssbs,strict-align,sve,sve2,sve2-aes,sve2-bitperm,sve2-sha3,sve2-sm4,sve2p1,tagged-globals,the,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tlb-rmi,tme,tpidr-el1,tpidr-el2,tpidr-el3,tpidrro-el0,tracev8.4,trbe,tsv110,uaops,use-experimental-zeroing-pseudos,use-postra-scheduler,use-reciprocal-square-root,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8a,v8r,v9.1a,v9.2a,v9.3a,v9.4a,v9a,vh,wfxt,xs,zcm,zcz,zcz-fp-workaround,zcz-gp"), + // TargetArch_wasm32: + str_lit("atomics,bulk-memory,exception-handling,extended-const,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call"), + // TargetArch_wasm64p32: + str_lit("atomics,bulk-memory,exception-handling,extended-const,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call"), +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global int target_microarch_counts[TargetArch_COUNT] = { + // TargetArch_Invalid: + 0, + // TargetArch_amd64: + 120, + // TargetArch_i386: + 120, + // TargetArch_arm32: + 90, + // TargetArch_arm64: + 63, + // TargetArch_wasm32: + 3, + // TargetArch_wasm64p32: + 3, +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global MicroarchFeatureList microarch_features_list[] = { + // TargetArch_amd64: + { str_lit("alderlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("amdfam10"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("athlon"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-4"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-fx"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-mp"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-tbird"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-xp"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64-sse3"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("atom"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("atom_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("atom_sse4_2_movbe"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("barcelona"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("bdver1"), str_lit("64bit,64bit-mode,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver3"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bdver4"), str_lit("64bit,64bit-mode,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bonnell"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("broadwell"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("btver1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-15bytenop,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, + { str_lit("btver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, + { str_lit("c3"), str_lit("3dnow,64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("c3-2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("cannonlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cascadelake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cooperlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("core-avx-i"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core-avx2"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core2"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_sse4_1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_ssse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2nd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_3rd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx_tsx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx_tsx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_aes_pclmulqdq"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("core_i7_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7-avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("emeraldrapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("generic"), str_lit("64bit,64bit-mode,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,sse,sse2,vzeroupper,x87") }, + { str_lit("geode"), str_lit("3dnow,3dnowa,64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("goldmont"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont-plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont_plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("grandridge"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids-d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids_d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("haswell"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("i386"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i486"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i586"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i686"), str_lit("64bit-mode,cmov,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("icelake-client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake-server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("ivybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("k6"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k6-2"), str_lit("3dnow,64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k6-3"), str_lit("3dnow,64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8-sse3"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("knl"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("knm"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("lakemont"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper") }, + { str_lit("meteorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("mic_avx512"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("nehalem"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("nocona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("opteron"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("opteron-sse3"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("penryn"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("pentium"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium3m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4_sse3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pentium_ii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_iii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_iii_no_xmm_regs"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_pro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentiumpro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("prescott"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("raptorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("rocketlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sandybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("sapphirerapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sierraforest"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("silvermont"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("skx"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake-avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake_avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("slm"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("tigerlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("tremont"), str_lit("64bit,64bit-mode,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("westmere"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("winchip-c6"), str_lit("64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("winchip2"), str_lit("3dnow,64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64"), str_lit("64bit,64bit-mode,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64-v2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("x86-64-v3"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("x86-64-v4"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("yonah"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("znver1"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver2"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver3"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver4"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + // TargetArch_i386: + { str_lit("alderlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("amdfam10"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("athlon"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("athlon-4"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon-fx"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-mp"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon-tbird"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("athlon-xp"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon64"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64-sse3"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("atom"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("atom_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("atom_sse4_2_movbe"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("barcelona"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("bdver1"), str_lit("32bit-mode,64bit,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver3"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bdver4"), str_lit("32bit-mode,64bit,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bonnell"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("broadwell"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("btver1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-15bytenop,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, + { str_lit("btver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, + { str_lit("c3"), str_lit("32bit-mode,3dnow,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("c3-2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("cannonlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cascadelake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cooperlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("core-avx-i"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core-avx2"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core2"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_sse4_1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_ssse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2nd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_3rd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx_tsx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx_tsx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_aes_pclmulqdq"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("core_i7_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7-avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("emeraldrapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("generic"), str_lit("32bit-mode,64bit,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,vzeroupper,x87") }, + { str_lit("geode"), str_lit("32bit-mode,3dnow,3dnowa,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("goldmont"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont-plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont_plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("grandridge"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids-d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids_d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("haswell"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("i386"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i486"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i586"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i686"), str_lit("32bit-mode,cmov,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("icelake-client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake-server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("ivybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("k6"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k6-2"), str_lit("32bit-mode,3dnow,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k6-3"), str_lit("32bit-mode,3dnow,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k8"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8-sse3"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("knl"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("knm"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("lakemont"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper") }, + { str_lit("meteorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("mic_avx512"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("nehalem"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("nocona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("opteron"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("opteron-sse3"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("penryn"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("pentium"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium-m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium3m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4_sse3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pentium_ii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium_iii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium_iii_no_xmm_regs"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium_m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium_pro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentiumpro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("prescott"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("raptorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("rocketlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sandybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("sapphirerapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sierraforest"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("silvermont"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("skx"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake-avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake_avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("slm"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("tigerlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("tremont"), str_lit("32bit-mode,64bit,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("westmere"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("winchip-c6"), str_lit("32bit-mode,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("winchip2"), str_lit("32bit-mode,3dnow,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("x86-64"), str_lit("32bit-mode,64bit,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64-v2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("x86-64-v3"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("x86-64-v4"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("yonah"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("znver1"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver2"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver3"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver4"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + // TargetArch_arm32: + { str_lit("arm1020e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm1020t"), str_lit("armv5t,v4t,v5t") }, + { str_lit("arm1022e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm10e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm10tdmi"), str_lit("armv5t,v4t,v5t") }, + { str_lit("arm1136j-s"), str_lit("armv6,dsp,v4t,v5t,v5te,v6") }, + { str_lit("arm1136jf-s"), str_lit("armv6,dsp,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,vfp2,vfp2sp") }, + { str_lit("arm1156t2-s"), str_lit("armv6t2,dsp,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m") }, + { str_lit("arm1156t2f-s"), str_lit("armv6t2,dsp,fp64,fpregs,fpregs64,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m,vfp2,vfp2sp") }, + { str_lit("arm1176jz-s"), str_lit("armv6kz,trustzone,v4t,v5t,v5te,v6,v6k") }, + { str_lit("arm1176jzf-s"), str_lit("armv6kz,fp64,fpregs,fpregs64,slowfpvmlx,trustzone,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, + { str_lit("arm710t"), str_lit("armv4t,v4t") }, + { str_lit("arm720t"), str_lit("armv4t,v4t") }, + { str_lit("arm7tdmi"), str_lit("armv4t,v4t") }, + { str_lit("arm7tdmi-s"), str_lit("armv4t,v4t") }, + { str_lit("arm8"), str_lit("armv4") }, + { str_lit("arm810"), str_lit("armv4") }, + { str_lit("arm9"), str_lit("armv4t,v4t") }, + { str_lit("arm920"), str_lit("armv4t,v4t") }, + { str_lit("arm920t"), str_lit("armv4t,v4t") }, + { str_lit("arm922t"), str_lit("armv4t,v4t") }, + { str_lit("arm926ej-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm940t"), str_lit("armv4t,v4t") }, + { str_lit("arm946e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm966e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm968e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm9e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm9tdmi"), str_lit("armv4t,v4t") }, + { str_lit("cortex-a12"), str_lit("a12,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a15"), str_lit("a15,aclass,armv7-a,avoid-partial-cpsr,d32,db,dont-widen-vmovs,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,muxed-units,neon,perfmon,ret-addr-stack,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align") }, + { str_lit("cortex-a17"), str_lit("a17,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a32"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a35"), str_lit("a35,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a5"), str_lit("a5,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-forwarding") }, + { str_lit("cortex-a53"), str_lit("a53,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a55"), str_lit("a55,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a57"), str_lit("a57,aclass,acquire-release,aes,armv8-a,avoid-partial-cpsr,cheap-predicable-cpsr,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a7"), str_lit("a7,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a710"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a72"), str_lit("a72,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a73"), str_lit("a73,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a75"), str_lit("a75,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a76"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a76ae"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a77"), str_lit("a77,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78c"), str_lit("a78c,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a8"), str_lit("a8,aclass,armv7-a,d32,db,dsp,fp64,fpregs,fpregs64,neon,nonpipelined-vfp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a9"), str_lit("a9,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,expand-fp-mlx,fp16,fp64,fpregs,fpregs64,mp,muxed-units,neon,neon-fpmovs,perfmon,prefer-vmovsr,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vldn-align,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-m0"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m0plus"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m1"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m23"), str_lit("8msecext,acquire-release,armv8-m.base,db,hwdiv,mclass,no-branch-predictor,no-movt,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m,v7clrex,v8m") }, + { str_lit("cortex-m3"), str_lit("armv7-m,db,hwdiv,loop-align,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("cortex-m33"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m35p"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m4"), str_lit("armv7e-m,db,dsp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m55"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,mclass,mve,mve.fp,no-branch-predictor,noarm,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m7"), str_lit("armv7e-m,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs64,hwdiv,m7,mclass,noarm,thumb-mode,thumb2,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m85"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,mclass,mve,mve.fp,noarm,pacbti,ras,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-r4"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,hwdiv,perfmon,r4,rclass,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("cortex-r4f"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,perfmon,r4,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r5"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,perfmon,r5,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r52"), str_lit("acquire-release,armv8-r,crc,d32,db,dfb,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,r52,rclass,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-r7"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,r7,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r8"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-x1"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-x1c"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1c,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cyclone"), str_lit("aclass,acquire-release,aes,armv8-a,avoid-movs-shop,avoid-partial-cpsr,crc,crypto,d32,db,disable-postra-scheduler,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,ret-addr-stack,sha2,slowfpvfmx,slowfpvmlx,swift,thumb2,trustzone,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,zcz") }, + { str_lit("ep9312"), str_lit("armv4t,v4t") }, + { str_lit("exynos-m3"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dont-widen-vmovs,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("exynos-m4"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("exynos-m5"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("generic"), str_lit("") }, + { str_lit("iwmmxt"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("krait"), str_lit("aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,krait,muxed-units,neon,perfmon,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vldn-align,vmlx-forwarding") }, + { str_lit("kryo"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,kryo,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("mpcore"), str_lit("armv6k,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, + { str_lit("mpcorenovfp"), str_lit("armv6k,v4t,v5t,v5te,v6,v6k") }, + { str_lit("neoverse-n1"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("neoverse-n2"), str_lit("aclass,acquire-release,armv9-a,bf16,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("neoverse-v1"), str_lit("aclass,acquire-release,aes,armv8.4-a,bf16,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("sc000"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("sc300"), str_lit("armv7-m,db,hwdiv,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("strongarm"), str_lit("armv4") }, + { str_lit("strongarm110"), str_lit("armv4") }, + { str_lit("strongarm1100"), str_lit("armv4") }, + { str_lit("strongarm1110"), str_lit("armv4") }, + { str_lit("swift"), str_lit("aclass,armv7-a,avoid-movs-shop,avoid-partial-cpsr,d32,db,disable-postra-scheduler,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,prefer-ishst,prof-unpr,ret-addr-stack,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,swift,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-hazards,wide-stride-vfp") }, + { str_lit("xscale"), str_lit("armv5te,v4t,v5t,v5te") }, + // TargetArch_arm64: + { str_lit("a64fx"), str_lit("CONTEXTIDREL2,a64fx,aggressive-fma,arith-bcc-fusion,ccpp,complxnum,crc,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rdm,sha2,store-pair-suppress,sve,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("ampere1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fuse-address,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("ampere1a"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1a,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fuse-address,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("apple-a10"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a10,arith-bcc-fusion,arith-cbz-fusion,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,lor,neon,pan,perfmon,rdm,sha2,store-pair-suppress,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a11"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a11,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a12"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a13"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a14"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a15"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a16"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a7"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-a8"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-a9"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-latest"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-m1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-m2"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-s4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-s5"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("carmel"), str_lit("CONTEXTIDREL2,aes,carmel,ccpp,crc,crypto,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,ras,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a34"), str_lit("a35,aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, + { str_lit("cortex-a35"), str_lit("a35,aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, + { str_lit("cortex-a510"), str_lit("CONTEXTIDREL2,a510,altnzcv,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a53"), str_lit("a53,aes,balance-fp-ops,crc,crypto,el2vmsa,el3,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,sha2,use-postra-scheduler,v8a") }, + { str_lit("cortex-a55"), str_lit("CONTEXTIDREL2,a55,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a57"), str_lit("a57,aes,balance-fp-ops,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,use-postra-scheduler,v8a") }, + { str_lit("cortex-a65"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a65ae"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a710"), str_lit("CONTEXTIDREL2,a710,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a715"), str_lit("CONTEXTIDREL2,a715,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a72"), str_lit("a72,aes,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,v8a") }, + { str_lit("cortex-a73"), str_lit("a73,aes,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,predictable-select-expensive,sha2,v8a") }, + { str_lit("cortex-a75"), str_lit("CONTEXTIDREL2,a75,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a76"), str_lit("CONTEXTIDREL2,a76,addr-lsl-fast,aes,alu-lsl-fast,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a76ae"), str_lit("CONTEXTIDREL2,a76,addr-lsl-fast,aes,alu-lsl-fast,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a77"), str_lit("CONTEXTIDREL2,a77,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78"), str_lit("CONTEXTIDREL2,a78,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78c"), str_lit("CONTEXTIDREL2,a78c,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-r82"), str_lit("CONTEXTIDREL2,ccidx,ccpp,complxnum,cortex-r82,crc,dit,dotprod,flagm,fp-armv8,fp16fml,fullfp16,jsconv,lse,neon,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8r") }, + { str_lit("cortex-x1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-x1c"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,lse2,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-x2"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-x2,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-x3"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x3,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cyclone"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("exynos-m3"), str_lit("addr-lsl-fast,aes,alu-lsl-fast,crc,crypto,el2vmsa,el3,exynos-cheap-as-move,exynosm3,force-32bit-jump-tables,fp-armv8,fuse-address,fuse-adrp-add,fuse-aes,fuse-csel,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a") }, + { str_lit("exynos-m4"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,crypto,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") }, + { str_lit("exynos-m5"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,crypto,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") }, + { str_lit("falkor"), str_lit("addr-lsl-fast,aes,alu-lsl-fast,crc,crypto,el2vmsa,el3,falkor,fp-armv8,neon,perfmon,predictable-select-expensive,rdm,sha2,slow-strqro-store,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") }, + { str_lit("generic"), str_lit("enable-select-opt,ete,fp-armv8,fuse-adrp-add,fuse-aes,neon,trbe,use-postra-scheduler") }, + { str_lit("kryo"), str_lit("addr-lsl-fast,aes,alu-lsl-fast,crc,crypto,el2vmsa,el3,fp-armv8,kryo,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") }, + { str_lit("neoverse-512tvb"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,crypto,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoverse512tvb,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, + { str_lit("neoverse-e1"), str_lit("CONTEXTIDREL2,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversee1,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("neoverse-n1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversen1,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("neoverse-n2"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,neoversen2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("neoverse-v1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,crypto,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoversev1,no-sve-fp-ld1r,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, + { str_lit("neoverse-v2"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,neoversev2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("saphira"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,am,ccidx,ccpp,complxnum,crc,crypto,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,saphira,sel2,sha2,spe,store-pair-suppress,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcz,zcz-gp") }, + { str_lit("thunderx"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderx,use-postra-scheduler,v8a") }, + { str_lit("thunderx2t99"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,crc,crypto,el2vmsa,el3,fp-armv8,lor,lse,neon,pan,predictable-select-expensive,rdm,sha2,store-pair-suppress,thunderx2t99,use-postra-scheduler,v8.1a,v8a,vh") }, + { str_lit("thunderx3t110"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,balance-fp-ops,ccidx,ccpp,complxnum,crc,crypto,el2vmsa,el3,fp-armv8,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,store-pair-suppress,strict-align,thunderx3t110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8a,vh") }, + { str_lit("thunderxt81"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt81,use-postra-scheduler,v8a") }, + { str_lit("thunderxt83"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt83,use-postra-scheduler,v8a") }, + { str_lit("thunderxt88"), str_lit("aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt88,use-postra-scheduler,v8a") }, + { str_lit("tsv110"), str_lit("CONTEXTIDREL2,aes,ccpp,complxnum,crc,crypto,dotprod,el2vmsa,el3,fp-armv8,fp16fml,fullfp16,fuse-aes,jsconv,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,spe,store-pair-suppress,tsv110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + // TargetArch_wasm32: + { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,mutable-globals,nontrapping-fptoint,sign-ext,simd128,tail-call") }, + { str_lit("generic"), str_lit("mutable-globals,sign-ext") }, + { str_lit("mvp"), str_lit("") }, + // TargetArch_wasm64p32: + { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,mutable-globals,nontrapping-fptoint,sign-ext,simd128,tail-call") }, + { str_lit("generic"), str_lit("mutable-globals,sign-ext") }, + { str_lit("mvp"), str_lit("") }, }; gb_global String target_endian_names[TargetEndian_COUNT] = { @@ -443,9 +894,9 @@ struct BuildContext { PtrMap defined_values; - BlockingMutex target_features_mutex; StringSet target_features_set; String target_features_string; + bool strict_target_features; String minimum_os_version_string; bool minimum_os_version_string_given; @@ -1596,48 +2047,53 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta #include "microsoft_craziness.h" #endif +// NOTE: the target feature and microarch lists are all sorted, so if it turns out to be slow (I don't think it will) +// a binary search is possible. -gb_internal Array split_by_comma(String const &list) { - isize n = 1; - for (isize i = 0; i < list.len; i++) { - if (list.text[i] == ',') { - n++; +gb_internal bool check_single_target_feature_is_valid(String const &feature_list, String const &feature) { + String_Iterator it = {feature_list, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + if (str == feature) { + return true; } } - auto res = array_make(heap_allocator(), n); - String s = list; - for (isize i = 0; i < n; i++) { - isize m = string_index_byte(s, ','); - if (m < 0) { - res[i] = s; - break; + return false; +} + +gb_internal bool check_target_feature_is_valid(String const &feature, TargetArchKind arch, String *invalid) { + String feature_list = target_features_list[arch]; + String_Iterator it = {feature, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + if (!check_single_target_feature_is_valid(feature_list, str)) { + if (invalid) *invalid = str; + return false; } - res[i] = substring(s, 0, m); - s = substring(s, m+1, s.len); } - return res; -} -gb_internal bool check_target_feature_is_valid(TokenPos pos, String const &feature) { - // TODO(bill): check_target_feature_is_valid return true; } -gb_internal bool check_target_feature_is_enabled(TokenPos pos, String const &target_feature_list) { - BuildContext *bc = &build_context; - mutex_lock(&bc->target_features_mutex); - defer (mutex_unlock(&bc->target_features_mutex)); - - auto items = split_by_comma(target_feature_list); - array_free(&items); - for (String const &item : items) { - if (!check_target_feature_is_valid(pos, item)) { - error(pos, "Target feature '%.*s' is not valid", LIT(item)); - return false; +gb_internal bool check_target_feature_is_valid_globally(String const &feature, String *invalid) { + String_Iterator it = {feature, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + + bool valid = false; + for (int arch = TargetArch_Invalid; arch < TargetArch_COUNT; arch += 1) { + if (check_target_feature_is_valid(str, cast(TargetArchKind)arch, invalid)) { + valid = true; + break; + } } - if (!string_set_exists(&bc->target_features_set, item)) { - error(pos, "Target feature '%.*s' is not enabled", LIT(item)); + + if (!valid) { + if (invalid) *invalid = str; return false; } } @@ -1645,54 +2101,35 @@ gb_internal bool check_target_feature_is_enabled(TokenPos pos, String const &tar return true; } -gb_internal void enable_target_feature(TokenPos pos, String const &target_feature_list) { - BuildContext *bc = &build_context; - mutex_lock(&bc->target_features_mutex); - defer (mutex_unlock(&bc->target_features_mutex)); - - auto items = split_by_comma(target_feature_list); - for (String const &item : items) { - if (!check_target_feature_is_valid(pos, item)) { - error(pos, "Target feature '%.*s' is not valid", LIT(item)); - continue; - } - - string_set_add(&bc->target_features_set, item); - } - array_free(&items); +gb_internal bool check_target_feature_is_valid_for_target_arch(String const &feature, String *invalid) { + return check_target_feature_is_valid(feature, build_context.metrics.arch, invalid); } - -gb_internal char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quotes, bool with_plus) { - isize len = 0; - isize i = 0; - for (String const &feature : build_context.target_features_set) { - if (i != 0) { - len += 1; +gb_internal bool check_target_feature_is_enabled(String const &feature, String *not_enabled) { + String_Iterator it = {feature, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + if (!string_set_exists(&build_context.target_features_set, str)) { + if (not_enabled) *not_enabled = str; + return false; } - len += feature.len; - if (with_quotes) len += 2; - if (with_plus) len += 1; - i += 1; } - char *features = gb_alloc_array(allocator, char, len+1); - len = 0; - i = 0; - for (String const &feature : build_context.target_features_set) { - if (i != 0) { - features[len++] = ','; - } - if (with_quotes) features[len++] = '"'; - if (with_plus) features[len++] = '+'; - gb_memmove(features + len, feature.text, feature.len); - len += feature.len; - if (with_quotes) features[len++] = '"'; - i += 1; - } - features[len++] = 0; + return true; +} - return features; +gb_internal bool check_target_feature_is_superset_of(String const &superset, String const &of, String *missing) { + String_Iterator it = {of, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + if (!check_single_target_feature_is_valid(superset, str)) { + if (missing) *missing = str; + return false; + } + } + return true; } // NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate. @@ -1983,10 +2420,6 @@ gb_internal bool init_build_paths(String init_filename) { } } - if (bc->target_features_string.len != 0) { - enable_target_feature({}, bc->target_features_string); - } - return true; } diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c3c217ec7..825fc6448 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1719,6 +1719,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_objc_register_selector: case BuiltinProc_objc_register_class: case BuiltinProc_atomic_type_is_lock_free: + case BuiltinProc_has_target_feature: // NOTE(bill): The first arg may be a Type, this will be checked case by case break; @@ -3663,6 +3664,41 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } + case BuiltinProc_has_target_feature: { + String features = str_lit(""); + + check_expr_or_type(c, operand, ce->args[0]); + + if (is_type_string(operand->type) && operand->mode == Addressing_Constant) { + GB_ASSERT(operand->value.kind == ExactValue_String); + features = operand->value.value_string; + } else { + Type *pt = base_type(operand->type); + if (pt->kind == Type_Proc) { + if (pt->Proc.require_target_feature.len != 0) { + GB_ASSERT(pt->Proc.enable_target_feature.len == 0); + features = pt->Proc.require_target_feature; + } else if (pt->Proc.enable_target_feature.len != 0) { + features = pt->Proc.enable_target_feature; + } else { + error(ce->args[0], "Expected the procedure type given to '%.*s' to have @(require_target_feature=\"...\") or @(enable_target_feature=\"...\")", LIT(builtin_name)); + } + } else { + error(ce->args[0], "Expected a constant string or procedure type for '%.*s'", LIT(builtin_name)); + } + } + + String invalid; + if (!check_target_feature_is_valid_globally(features, &invalid)) { + error(ce->args[0], "Target feature '%.*s' is not a valid target feature", LIT(invalid)); + } + + operand->value = exact_value_bool(check_target_feature_is_enabled(features, nullptr)); + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + } + case BuiltinProc_soa_struct: { Operand x = {}; Operand y = {}; @@ -6014,7 +6050,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } - enable_target_feature({}, str_lit("atomics")); + if (!check_target_feature_is_enabled(str_lit("atomics"), nullptr)) { + error(call, "'%.*s' requires target feature 'atomics' to be enabled, enable it with -target-features:\"atomics\" or choose a different -microarch", LIT(builtin_name)); + return false; + } Operand ptr = {}; Operand expected = {}; @@ -6068,7 +6107,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } - enable_target_feature({}, str_lit("atomics")); + if (!check_target_feature_is_enabled(str_lit("atomics"), nullptr)) { + error(call, "'%.*s' requires target feature 'atomics' to be enabled, enable it with -target-features:\"atomics\" or choose a different -microarch", LIT(builtin_name)); + return false; + } Operand ptr = {}; Operand waiters = {}; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 952a877a4..5b9486873 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -886,17 +886,37 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { check_objc_methods(ctx, e, ac); - if (ac.require_target_feature.len != 0 && ac.enable_target_feature.len != 0) { - error(e->token, "Attributes @(require_target_feature=...) and @(enable_target_feature=...) cannot be used together"); - } else if (ac.require_target_feature.len != 0) { - if (check_target_feature_is_enabled(e->token.pos, ac.require_target_feature)) { - e->Procedure.target_feature = ac.require_target_feature; - } else { - e->Procedure.target_feature_disabled = true; + { + if (ac.require_target_feature.len != 0 && ac.enable_target_feature.len != 0) { + error(e->token, "A procedure cannot have both @(require_target_feature=\"...\") and @(enable_target_feature=\"...\")"); + } + + if (build_context.strict_target_features && ac.enable_target_feature.len != 0) { + ac.require_target_feature = ac.enable_target_feature; + ac.enable_target_feature.len = 0; + } + + if (ac.require_target_feature.len != 0) { + pt->require_target_feature = ac.require_target_feature; + String invalid; + if (!check_target_feature_is_valid_globally(ac.require_target_feature, &invalid)) { + error(e->token, "Required target feature '%.*s' is not a valid target feature", LIT(invalid)); + } else if (!check_target_feature_is_enabled(ac.require_target_feature, nullptr)) { + e->flags |= EntityFlag_Disabled; + } + } else if (ac.enable_target_feature.len != 0) { + + // NOTE: disallow wasm, features on that arch are always global to the module. + if (is_arch_wasm()) { + error(e->token, "@(enable_target_feature=\"...\") is not allowed on wasm, features for wasm must be declared globally"); + } + + pt->enable_target_feature = ac.enable_target_feature; + String invalid; + if (!check_target_feature_is_valid_globally(ac.enable_target_feature, &invalid)) { + error(e->token, "Procedure enabled target feature '%.*s' is not a valid target feature", LIT(invalid)); + } } - } else if (ac.enable_target_feature.len != 0) { - enable_target_feature(e->token.pos, ac.enable_target_feature); - e->Procedure.target_feature = ac.enable_target_feature; } switch (e->Procedure.optimization_mode) { @@ -1370,6 +1390,10 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, D continue; } + if (p->flags & EntityFlag_Disabled) { + continue; + } + String name = p->token.string; for (isize k = j+1; k < pge->entities.count; k++) { @@ -1387,6 +1411,10 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, D ERROR_BLOCK(); + if (q->flags & EntityFlag_Disabled) { + continue; + } + ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type); bool both_have_where_clauses = false; if (p->decl_info->proc_lit != nullptr && q->decl_info->proc_lit != nullptr) { @@ -1423,6 +1451,7 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, D break; case ProcOverload_ParamCount: case ProcOverload_ParamTypes: + case ProcOverload_TargetFeatures: // This is okay :) break; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 06d0a8b12..490c9aae7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6526,12 +6526,17 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, array_add(&proc_entities, proc); } + int max_matched_features = 0; gbString expr_name = expr_to_string(operand->expr); defer (gb_string_free(expr_name)); for_array(i, procs) { Entity *p = procs[i]; + if (p->flags & EntityFlag_Disabled) { + continue; + } + Type *pt = base_type(p->type); if (pt != nullptr && is_type_proc(pt)) { CallArgumentData data = {}; @@ -6562,11 +6567,24 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, item.score += assign_score_function(1); } + max_matched_features = gb_max(max_matched_features, matched_target_features(&pt->Proc)); + item.index = index; array_add(&valids, item); } } + if (max_matched_features > 0) { + for_array(i, valids) { + Entity *p = procs[valids[i].index]; + Type *t = base_type(p->type); + GB_ASSERT(t->kind == Type_Proc); + + int matched = matched_target_features(&t->Proc); + valids[i].score += assign_score_function(max_matched_features-matched); + } + } + if (valids.count > 1) { array_sort(valids, valid_index_and_score_cmp); i64 best_score = valids[0].score; @@ -6708,7 +6726,11 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, ERROR_BLOCK(); error(operand->expr, "Ambiguous procedure group call '%s' that match with the given arguments", expr_name); - print_argument_types(); + if (positional_operands.count == 0 && named_operands.count == 0) { + error_line("\tNo given arguments\n"); + } else { + print_argument_types(); + } for (auto const &valid : valids) { Entity *proc = proc_entities[valid.index]; @@ -7553,8 +7575,11 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } + bool is_call_inlined = false; + switch (inlining) { case ProcInlining_inline: + is_call_inlined = true; if (proc != nullptr) { Entity *e = entity_from_expr(proc); if (e != nullptr && e->kind == Entity_Procedure) { @@ -7570,6 +7595,47 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c break; case ProcInlining_no_inline: break; + case ProcInlining_none: + if (proc != nullptr) { + Entity *e = entity_from_expr(proc); + if (e != nullptr && e->kind == Entity_Procedure) { + DeclInfo *decl = e->decl_info; + if (decl->proc_lit) { + ast_node(pl, ProcLit, decl->proc_lit); + if (pl->inlining == ProcInlining_inline) { + is_call_inlined = true; + } + } + } + } + } + + { + String invalid; + if (pt->kind == Type_Proc && pt->Proc.require_target_feature.len != 0) { + if (!check_target_feature_is_valid_for_target_arch(pt->Proc.require_target_feature, &invalid)) { + error(call, "Called procedure requires target feature '%.*s' which is invalid for the build target", LIT(invalid)); + } else if (!check_target_feature_is_enabled(pt->Proc.require_target_feature, &invalid)) { + error(call, "Calling this procedure requires target feature '%.*s' to be enabled", LIT(invalid)); + } + } + + if (pt->kind == Type_Proc && pt->Proc.enable_target_feature.len != 0) { + if (!check_target_feature_is_valid_for_target_arch(pt->Proc.enable_target_feature, &invalid)) { + error(call, "Called procedure enables target feature '%.*s' which is invalid for the build target", LIT(invalid)); + } + + // NOTE: Due to restrictions in LLVM you can not inline calls with a superset of features. + if (is_call_inlined) { + GB_ASSERT(c->curr_proc_decl); + GB_ASSERT(c->curr_proc_decl->entity); + GB_ASSERT(c->curr_proc_decl->entity->type->kind == Type_Proc); + String scope_features = c->curr_proc_decl->entity->type->Proc.enable_target_feature; + if (!check_target_feature_is_superset_of(scope_features, pt->Proc.enable_target_feature, &invalid)) { + error(call, "Inlined procedure enables target feature '%.*s', this requires the calling procedure to at least enable the same feature", LIT(invalid)); + } + } + } } operand->expr = call; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index c15ec7137..8419c6568 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -44,6 +44,8 @@ enum BuiltinProcId { // "Intrinsics" BuiltinProc_is_package_imported, + BuiltinProc_has_target_feature, + BuiltinProc_transpose, BuiltinProc_outer_product, BuiltinProc_hadamard_product, @@ -354,6 +356,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { // "Intrinsics" {STR_LIT("is_package_imported"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("has_target_feature"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("transpose"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("outer_product"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("hadamard_product"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/entity.cpp b/src/entity.cpp index a12e1d0a6..d76d5f441 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -252,10 +252,8 @@ struct Entity { bool is_foreign : 1; bool is_export : 1; bool generated_from_polymorphic : 1; - bool target_feature_disabled : 1; bool entry_point_only : 1; bool has_instrumentation : 1; - String target_feature; } Procedure; struct { Array entities; @@ -502,4 +500,4 @@ gb_internal bool is_entity_local_variable(Entity *e) { return ((e->scope->flags &~ ScopeFlag_ContextDefined) == 0) || (e->scope->flags & ScopeFlag_Proc) != 0; -} \ No newline at end of file +} diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 4b94cf020..fad130b99 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -41,6 +41,37 @@ String get_default_microarchitecture() { return default_march; } +String get_final_microarchitecture() { + BuildContext *bc = &build_context; + + String microarch = bc->microarch; + if (microarch.len == 0) { + microarch = get_default_microarchitecture(); + } else if (microarch == str_lit("native")) { + microarch = make_string_c(LLVMGetHostCPUName()); + } + return microarch; +} + +gb_internal String get_default_features() { + BuildContext *bc = &build_context; + + int off = 0; + for (int i = 0; i < bc->metrics.arch; i += 1) { + off += target_microarch_counts[i]; + } + + String microarch = get_final_microarchitecture(); + for (int i = off; i < off+target_microarch_counts[bc->metrics.arch]; i += 1) { + if (microarch_features_list[i].microarch == microarch) { + return microarch_features_list[i].features; + } + } + + GB_PANIC("unknown microarch"); + return {}; +} + gb_internal void lb_add_foreign_library_path(lbModule *m, Entity *e) { if (e == nullptr) { return; @@ -2468,69 +2499,24 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { code_mode = LLVMCodeModelKernel; } - String host_cpu_name = copy_string(permanent_allocator(), make_string_c(LLVMGetHostCPUName())); - String llvm_cpu = get_default_microarchitecture(); - char const *llvm_features = ""; - if (build_context.microarch.len != 0) { - if (build_context.microarch == "native") { - llvm_cpu = host_cpu_name; - } else { - llvm_cpu = copy_string(permanent_allocator(), build_context.microarch); - } - if (llvm_cpu == host_cpu_name) { - llvm_features = LLVMGetHostCPUFeatures(); + String llvm_cpu = get_final_microarchitecture(); + + gbString llvm_features = gb_string_make(temporary_allocator(), ""); + String_Iterator it = {build_context.target_features_string, 0}; + bool first = true; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + if (!first) { + llvm_features = gb_string_appendc(llvm_features, ","); } - } + first = false; - // 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")); + llvm_features = gb_string_appendc(llvm_features, "+"); + llvm_features = gb_string_append_length(llvm_features, str.text, str.len); } - */ - if (build_context.target_features_set.entries.count != 0) { - // Prefix all of the features with a `+`, because we are - // enabling additional features. - char const *additional_features = target_features_set_to_cstring(permanent_allocator(), false, true); - - String f_string = make_string_c(llvm_features); - String a_string = make_string_c(additional_features); - isize f_len = f_string.len; - - if (f_len == 0) { - // The common case is that llvm_features is empty, so - // the target_features_set additions can be used as is. - llvm_features = additional_features; - } else { - // The user probably specified `-microarch:native`, so - // llvm_features is populated by LLVM's idea of what - // the host CPU supports. - // - // As far as I can tell, (which is barely better than - // wild guessing), a bitset is formed by parsing the - // string left to right. - // - // So, llvm_features + ',' + additonal_features, will - // makes the target_features_set override llvm_features. - - char *tmp = gb_alloc_array(permanent_allocator(), char, f_len + 1 + a_string.len + 1); - isize len = 0; - - // tmp = f_string - gb_memmove(tmp, f_string.text, f_string.len); - len += f_string.len; - // tmp += ',' - tmp[len++] = ','; - // tmp += a_string - gb_memmove(tmp + len, a_string.text, a_string.len); - len += a_string.len; - // tmp += NUL - tmp[len++] = 0; - - llvm_features = tmp; - } - } + debugf("CPU: %.*s, Features: %s\n", LIT(llvm_cpu), llvm_features); // GB_ASSERT_MSG(LLVMTargetHasAsmBackend(target)); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index f73698d34..898c9ac31 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -177,17 +177,24 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i break; } - if (!entity->Procedure.target_feature_disabled && - entity->Procedure.target_feature.len != 0) { - auto features = split_by_comma(entity->Procedure.target_feature); - for_array(i, features) { - String feature = features[i]; - LLVMAttributeRef ref = LLVMCreateStringAttribute( - m->ctx, - cast(char const *)feature.text, cast(unsigned)feature.len, - "", 0); - LLVMAddAttributeAtIndex(p->value, LLVMAttributeIndex_FunctionIndex, ref); + if (pt->Proc.enable_target_feature.len != 0) { + gbString feature_str = gb_string_make(temporary_allocator(), ""); + + String_Iterator it = {pt->Proc.enable_target_feature, 0}; + bool first = true; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + if (!first) { + feature_str = gb_string_appendc(feature_str, ","); + } + first = false; + + feature_str = gb_string_appendc(feature_str, "+"); + feature_str = gb_string_append_length(feature_str, str.text, str.len); } + + lb_add_attribute_to_proc_with_string(m, p->value, make_string_c("target-features"), make_string_c(feature_str)); } if (entity->flags & EntityFlag_Cold) { diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index c01ab0692..db99ebc99 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1708,7 +1708,8 @@ gb_internal lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValu if (is_possible) { switch (build_context.metrics.arch) { case TargetArch_amd64: - if (type_size_of(t) == 2) { + // NOTE: using the intrinsic when not supported causes slow codegen (See #2928). + if (type_size_of(t) == 2 || !check_target_feature_is_enabled(str_lit("fma"), nullptr)) { is_possible = false; } break; diff --git a/src/main.cpp b/src/main.cpp index ee7de7f81..93685acb9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -272,6 +272,7 @@ enum BuildFlagKind { BuildFlag_ExtraAssemblerFlags, BuildFlag_Microarch, BuildFlag_TargetFeatures, + BuildFlag_StrictTargetFeatures, BuildFlag_MinimumOSVersion, BuildFlag_NoThreadLocal, @@ -467,6 +468,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_TargetFeatures, str_lit("target-features"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_StrictTargetFeatures, str_lit("strict-target-features"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_MinimumOSVersion, str_lit("minimum-os-version"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build); @@ -1083,6 +1085,9 @@ gb_internal bool parse_build_flags(Array args) { string_to_lower(&build_context.target_features_string); break; } + case BuildFlag_StrictTargetFeatures: + build_context.strict_target_features = true; + break; case BuildFlag_MinimumOSVersion: { GB_ASSERT(value.kind == ExactValue_String); build_context.minimum_os_version_string = value.value_string; @@ -1981,7 +1986,20 @@ 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(3, "-microarch:\"?\" for a list"); + print_usage_line(0, ""); + + print_usage_line(1, "-target-features:"); + print_usage_line(2, "Specifies CPU features to enable on top of the enabled features implied by -microarch."); + print_usage_line(2, "Examples:"); + print_usage_line(3, "-target-features:atomics"); + print_usage_line(3, "-target-features:\"sse2,aes\""); + print_usage_line(3, "-target-features:\"?\" for a list"); + print_usage_line(0, ""); + + print_usage_line(1, "-strict-target-features"); + print_usage_line(2, "Makes @(enable_target_features=\"...\") behave the same way as @(require_target_features=\"...\")."); + print_usage_line(2, "This enforces that all generated code uses features supported by the combination of -target, -microarch, and -target-features."); print_usage_line(0, ""); print_usage_line(1, "-reloc-mode:"); @@ -2663,7 +2681,7 @@ int main(int arg_count, char const **arg_ptr) { // Check chosen microarchitecture. If not found or ?, print list. bool print_microarch_list = true; - if (build_context.microarch.len == 0) { + if (build_context.microarch.len == 0 || build_context.microarch == str_lit("native")) { // Autodetect, no need to print list. print_microarch_list = false; } else { @@ -2680,6 +2698,11 @@ int main(int arg_count, char const **arg_ptr) { } } + // Set and check build paths... + if (!init_build_paths(init_filename)) { + return 1; + } + String default_march = get_default_microarchitecture(); if (print_microarch_list) { if (build_context.microarch != "?") { @@ -2703,13 +2726,57 @@ int main(int arg_count, char const **arg_ptr) { return 0; } - // Set and check build paths... - if (!init_build_paths(init_filename)) { - return 1; + String march = get_final_microarchitecture(); + String default_features = get_default_features(); + { + String_Iterator it = {default_features, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + string_set_add(&build_context.target_features_set, str); + } + } + + if (build_context.target_features_string.len != 0) { + String_Iterator target_it = {build_context.target_features_string, 0}; + for (;;) { + String item = string_split_iterator(&target_it, ','); + if (item == "") break; + + String invalid; + if (!check_target_feature_is_valid_for_target_arch(item, &invalid) && item != str_lit("help")) { + if (item != str_lit("?")) { + gb_printf_err("Unkown target feature '%.*s'.\n", LIT(invalid)); + } + gb_printf("Possible -target-features for target %.*s are:\n", LIT(target_arch_names[build_context.metrics.arch])); + gb_printf("\n"); + + String feature_list = target_features_list[build_context.metrics.arch]; + String_Iterator it = {feature_list, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + if (check_single_target_feature_is_valid(default_features, str)) { + if (has_ansi_terminal_colours()) { + gb_printf("\t%.*s\x1b[38;5;244m (implied by target microarch %.*s)\x1b[0m\n", LIT(str), LIT(march)); + } else { + gb_printf("\t%.*s (implied by current microarch %.*s)\n", LIT(str), LIT(march)); + } + } else { + gb_printf("\t%.*s\n", LIT(str)); + } + } + + return 1; + } + + string_set_add(&build_context.target_features_set, item); + } } if (build_context.show_debug_messages) { - debugf("Selected microarch: %.*s\n", LIT(default_march)); + debugf("Selected microarch: %.*s\n", LIT(march)); + debugf("Default microarch features: %.*s\n", LIT(default_features)); for_array(i, build_context.build_paths) { String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]); debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path)); diff --git a/src/types.cpp b/src/types.cpp index 18cb12ea1..3ec05059f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -184,6 +184,8 @@ struct TypeProc { isize specialization_count; ProcCallingConvention calling_convention; i32 variadic_index; + String require_target_feature; + String enable_target_feature; // TODO(bill): Make this a flag set rather than bools bool variadic; bool require_results; @@ -2991,7 +2993,22 @@ gb_internal Type *union_tag_type(Type *u) { return t_uint; } +gb_internal int matched_target_features(TypeProc *t) { + if (t->require_target_feature.len == 0) { + return 0; + } + int matches = 0; + String_Iterator it = {t->require_target_feature, 0}; + for (;;) { + String str = string_split_iterator(&it, ','); + if (str == "") break; + if (check_target_feature_is_valid_for_target_arch(str, nullptr)) { + matches += 1; + } + } + return matches; +} enum ProcTypeOverloadKind { ProcOverload_Identical, // The types are identical @@ -3003,6 +3020,7 @@ enum ProcTypeOverloadKind { ProcOverload_ResultCount, ProcOverload_ResultTypes, ProcOverload_Polymorphic, + ProcOverload_TargetFeatures, ProcOverload_NotProcedure, @@ -3060,6 +3078,10 @@ gb_internal ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) } } + if (matched_target_features(&px) != matched_target_features(&py)) { + return ProcOverload_TargetFeatures; + } + if (px.params != nullptr && py.params != nullptr) { Entity *ex = px.params->Tuple.variables[0]; Entity *ey = py.params->Tuple.variables[0]; -- cgit v1.2.3 From 05a17048982dea73ac0c7db1e743582abf73233b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 7 May 2024 11:24:21 +0100 Subject: Fix #3464 --- src/check_builtin.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 825fc6448..3d31ec75d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2023,6 +2023,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Selection sel = lookup_field(type, field_name, false); if (sel.entity == nullptr) { + ERROR_BLOCK(); gbString type_str = type_to_string_shorthand(type); error(ce->args[0], "'%s' has no field named '%.*s'", type_str, LIT(field_name)); @@ -2096,6 +2097,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Selection sel = lookup_field(type, field_name, false); if (sel.entity == nullptr) { + ERROR_BLOCK(); gbString type_str = type_to_string_shorthand(type); error(ce->args[0], "'%s' has no field named '%.*s'", type_str, LIT(field_name)); @@ -5837,6 +5839,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Selection sel = lookup_field(type, field_name, false); if (sel.entity == nullptr) { + ERROR_BLOCK(); gbString type_str = type_to_string(bt); error(ce->args[0], "'%s' has no field named '%.*s'", type_str, LIT(field_name)); -- cgit v1.2.3 From b0f0e4d02a88b27e04d9d7241959107ce08ff592 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 9 May 2024 15:47:09 +0100 Subject: Add intrinsics `type_bit_set_elem_type` & `type_bit_set_underlying_type` --- base/intrinsics/intrinsics.odin | 21 ++++++++++------- src/check_builtin.cpp | 52 +++++++++++++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 6 +++++ 3 files changed, 70 insertions(+), 9 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index d887f8dcc..0c4e5d6c3 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -169,15 +169,18 @@ 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($T: typeid) -> typeid where type_is_union(T) --- -type_union_tag_offset :: proc($T: typeid) -> uintptr 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 --- +type_is_variant_of :: proc($U, $V: typeid) -> bool 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) -> uintptr 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_bit_set_elem_type :: proc($T: typeid) -> typeid where type_is_bit_set(T) --- +type_bit_set_underlying_type :: proc($T: typeid) -> typeid where type_is_bit_set(T) --- + +type_has_field :: proc($T: typeid, $name: string) -> bool --- type_field_type :: proc($T: typeid, $name: string) -> typeid --- type_proc_parameter_count :: proc($T: typeid) -> int where type_is_proc(T) --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 3d31ec75d..c7d27cf38 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5433,6 +5433,58 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->value = exact_value_i64(u->Union.kind == UnionType_no_nil ? 0 : 1); } break; + case BuiltinProc_type_bit_set_elem_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 *bs = operand->type; + + if (!is_type_bit_set(bs)) { + error(operand->expr, "Expected a bit_set type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + bs = base_type(bs); + GB_ASSERT(bs->kind == Type_BitSet); + + operand->mode = Addressing_Type; + operand->type = bs->BitSet.elem; + } break; + + case BuiltinProc_type_bit_set_underlying_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 *bs = operand->type; + + if (!is_type_bit_set(bs)) { + error(operand->expr, "Expected a bit_set type for '%.*s'", LIT(builtin_name)); + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + return false; + } + + bs = base_type(bs); + GB_ASSERT(bs->kind == Type_BitSet); + + operand->mode = Addressing_Type; + operand->type = bit_set_to_int(bs); + } break; + case BuiltinProc_type_union_variant_count: { if (operand->mode != Addressing_Type) { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 8419c6568..04a8bb848 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -269,6 +269,9 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_variant_type_of, BuiltinProc_type_variant_index_of, + BuiltinProc_type_bit_set_elem_type, + BuiltinProc_type_bit_set_underlying_type, + BuiltinProc_type_struct_field_count, BuiltinProc_type_proc_parameter_count, @@ -577,6 +580,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {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_bit_set_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_bit_set_underlying_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_proc_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From c9b1c99a4057b7e3f6caee3fb37cf85ca29a7fc9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 16 May 2024 16:27:09 +0100 Subject: Fix `soa_zip` and `soa_unzip` --- src/check_builtin.cpp | 4 ++-- src/llvm_backend_utility.cpp | 14 +++++++++++--- src/types.cpp | 10 ++++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c7d27cf38..4636d810a 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3428,8 +3428,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As auto types = slice_make(permanent_allocator(), t->Struct.fields.count-1); for_array(i, types) { Entity *f = t->Struct.fields[i]; - GB_ASSERT(f->type->kind == Type_Pointer); - types[i] = alloc_type_slice(f->type->Pointer.elem); + GB_ASSERT(f->type->kind == Type_MultiPointer); + types[i] = alloc_type_slice(f->type->MultiPointer.elem); } operand->type = alloc_type_tuple_from_field_types(types.data, types.count, false, false); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 8b046c784..5ebe0ddd9 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -328,6 +328,7 @@ gb_internal lbValue lb_soa_zip(lbProcedure *p, AstCallExpr *ce, TypeAndValue con lbAddr res = lb_add_local_generated(p, tv.type, true); for_array(i, slices) { lbValue src = lb_slice_elem(p, slices[i]); + src = lb_emit_conv(p, src, alloc_type_pointer_to_multi_pointer(src.type)); lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i); lb_emit_store(p, dst, src); } @@ -1559,19 +1560,26 @@ gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isiz return lb_emit_load(p, ptr); } - gb_internal void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len) { Type *t = lb_addr_type(slice); GB_ASSERT(is_type_slice(t)); lbValue ptr = lb_addr_get_ptr(p, slice); - lb_emit_store(p, lb_emit_struct_ep(p, ptr, 0), base_elem); + lbValue data = lb_emit_struct_ep(p, ptr, 0); + if (are_types_identical(type_deref(base_elem.type, true), type_deref(type_deref(data.type), true))) { + base_elem = lb_emit_conv(p, base_elem, type_deref(data.type)); + } + lb_emit_store(p, data, base_elem); lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len); } gb_internal void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue base_elem, lbValue len) { Type *t = lb_addr_type(string); GB_ASSERT(is_type_string(t)); lbValue ptr = lb_addr_get_ptr(p, string); - lb_emit_store(p, lb_emit_struct_ep(p, ptr, 0), base_elem); + lbValue data = lb_emit_struct_ep(p, ptr, 0); + if (are_types_identical(type_deref(base_elem.type, true), type_deref(type_deref(data.type), true))) { + base_elem = lb_emit_conv(p, base_elem, type_deref(data.type)); + } + lb_emit_store(p, data, base_elem); lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len); } diff --git a/src/types.cpp b/src/types.cpp index 47ed86f7a..390ee842a 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -988,6 +988,16 @@ gb_internal Type *alloc_type_soa_pointer(Type *elem) { return t; } +gb_internal Type *alloc_type_pointer_to_multi_pointer(Type *ptr) { + Type *original_type = ptr; + ptr = base_type(ptr); + if (ptr->kind == Type_Pointer) { + return alloc_type_multi_pointer(ptr->Pointer.elem); + } else if (ptr->kind != Type_MultiPointer) { + GB_PANIC("Invalid type: %s", type_to_string(original_type)); + } + return original_type; +} gb_internal Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = nullptr) { if (generic_count != nullptr) { -- cgit v1.2.3 From 5473758467610e8d18581f0dab11dd5f5c416484 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 20 May 2024 10:15:21 +0100 Subject: Add intrinsics `type_is_matrix_row_major` & `type_is_matrix_column_major` --- base/intrinsics/intrinsics.odin | 3 +++ src/check_builtin.cpp | 28 ++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 6 ++++++ 3 files changed, 37 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 0c4e5d6c3..8873f3bbc 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -167,6 +167,9 @@ type_is_matrix :: proc($T: typeid) -> bool --- type_has_nil :: proc($T: typeid) -> bool --- +type_is_matrix_row_major :: proc($T: typeid) -> bool where type_is_matrix(T) --- +type_is_matrix_column_major :: proc($T: typeid) -> bool where type_is_matrix(T) --- + type_is_specialization_of :: proc($T, $S: typeid) -> bool --- type_is_variant_of :: proc($U, $V: typeid) -> bool where type_is_union(U) --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 4636d810a..5400f83f6 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5221,6 +5221,34 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = t_untyped_bool; break; + + case BuiltinProc_type_is_matrix_row_major: + case BuiltinProc_type_is_matrix_column_major: + { + Operand op = {}; + Type *bt = check_type(c, ce->args[0]); + Type *type = base_type(bt); + if (type == nullptr || type == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (type->kind != Type_Matrix) { + gbString s = type_to_string(bt); + error(ce->args[0], "Expected a matrix type for '%.*s', got '%s'", LIT(builtin_name), s); + gb_string_free(s); + return false; + } + + if (id == BuiltinProc_type_is_matrix_row_major) { + operand->value = exact_value_bool(bt->Matrix.is_row_major == true); + } else { + operand->value = exact_value_bool(bt->Matrix.is_row_major == false); + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; + } + case BuiltinProc_type_has_field: { Operand op = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 04a8bb848..5f98bb7b3 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -256,6 +256,9 @@ BuiltinProc__type_simple_boolean_begin, BuiltinProc__type_simple_boolean_end, + BuiltinProc_type_is_matrix_row_major, + BuiltinProc_type_is_matrix_column_major, + BuiltinProc_type_has_field, BuiltinProc_type_field_type, @@ -567,6 +570,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_has_nil"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_matrix_row_major"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_matrix_column_major"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_has_field"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_field_type"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From 856537f0ce11bd0e966fc6647b949fc99373ef29 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 20 May 2024 15:54:53 +0100 Subject: Fix #3603 --- src/check_builtin.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 5400f83f6..d85e94db3 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1092,7 +1092,13 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String BlockingMutex *ignore_mutex = nullptr; bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); + if (!ok) { + if (err_on_not_found) { + error(ce->proc, "Failed to `#%.*s` file: %.*s; invalid file or cannot be found", LIT(builtin_name), LIT(original_string)); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return false; + } } MUTEX_GUARD(&c->info->load_file_mutex); -- cgit v1.2.3 From 9b78061c8fb83202973d509b9af24f0a12786958 Mon Sep 17 00:00:00 2001 From: Dudejoe870 Date: Tue, 28 May 2024 22:25:16 -0500 Subject: Initial hash directive implementation --- src/check_builtin.cpp | 167 +++++++++++++++++++++++++++++++++++--------------- src/check_expr.cpp | 3 +- 2 files changed, 120 insertions(+), 50 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index d85e94db3..aa3be0bbd 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1403,6 +1403,65 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c return result; } +gb_internal bool check_hash_kind(CheckerContext *c, Ast *call, String const &hash_kind, u8 const *data, isize data_size, u64 *hash_value) { + ast_node(ce, CallExpr, call); + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + GB_ASSERT(name == "load_hash" || name == "hash"); + + String supported_hashes[] = { + str_lit("adler32"), + str_lit("crc32"), + str_lit("crc64"), + str_lit("fnv32"), + str_lit("fnv64"), + str_lit("fnv32a"), + str_lit("fnv64a"), + str_lit("murmur32"), + str_lit("murmur64"), + }; + + bool hash_found = false; + for (isize i = 0; i < gb_count_of(supported_hashes); i++) { + if (supported_hashes[i] == hash_kind) { + hash_found = true; + break; + } + } + if (!hash_found) { + ERROR_BLOCK(); + error(ce->proc, "Invalid hash kind passed to `#%.*s`, got: %.*s", LIT(name), LIT(hash_kind)); + error_line("\tAvailable hash kinds:\n"); + for (isize i = 0; i < gb_count_of(supported_hashes); i++) { + error_line("\t%.*s\n", LIT(supported_hashes[i])); + } + return false; + } + + if (hash_kind == "adler32") { + *hash_value = gb_adler32(data, data_size); + } else if (hash_kind == "crc32") { + *hash_value = gb_crc32(data, data_size); + } else if (hash_kind == "crc64") { + *hash_value = gb_crc64(data, data_size); + } else if (hash_kind == "fnv32") { + *hash_value = gb_fnv32(data, data_size); + } else if (hash_kind == "fnv64") { + *hash_value = gb_fnv64(data, data_size); + } else if (hash_kind == "fnv32a") { + *hash_value = fnv32a(data, data_size); + } else if (hash_kind == "fnv64a") { + *hash_value = fnv64a(data, data_size); + } else if (hash_kind == "murmur32") { + *hash_value = gb_murmur32(data, data_size); + } else if (hash_kind == "murmur64") { + *hash_value = gb_murmur64(data, data_size); + } else { + compiler_error("unhandled hash kind: %.*s", LIT(hash_kind)); + } + return true; +} + gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) { @@ -1480,35 +1539,6 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o String original_string = o.value.value_string; String hash_kind = o_hash.value.value_string; - String supported_hashes[] = { - str_lit("adler32"), - str_lit("crc32"), - str_lit("crc64"), - str_lit("fnv32"), - str_lit("fnv64"), - str_lit("fnv32a"), - str_lit("fnv64a"), - str_lit("murmur32"), - str_lit("murmur64"), - }; - - bool hash_found = false; - for (isize i = 0; i < gb_count_of(supported_hashes); i++) { - if (supported_hashes[i] == hash_kind) { - hash_found = true; - break; - } - } - if (!hash_found) { - ERROR_BLOCK(); - error(ce->proc, "Invalid hash kind passed to `#load_hash`, got: %.*s", LIT(hash_kind)); - error_line("\tAvailable hash kinds:\n"); - for (isize i = 0; i < gb_count_of(supported_hashes); i++) { - error_line("\t%.*s\n", LIT(supported_hashes[i])); - } - return false; - } - LoadFileCache *cache = nullptr; if (cache_load_file_directive(c, call, original_string, true, &cache)) { MUTEX_GUARD(&c->info->load_file_mutex); @@ -1520,26 +1550,9 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o } else { u8 *data = cache->data.text; isize file_size = cache->data.len; - if (hash_kind == "adler32") { - hash_value = gb_adler32(data, file_size); - } else if (hash_kind == "crc32") { - hash_value = gb_crc32(data, file_size); - } else if (hash_kind == "crc64") { - hash_value = gb_crc64(data, file_size); - } else if (hash_kind == "fnv32") { - hash_value = gb_fnv32(data, file_size); - } else if (hash_kind == "fnv64") { - hash_value = gb_fnv64(data, file_size); - } else if (hash_kind == "fnv32a") { - hash_value = fnv32a(data, file_size); - } else if (hash_kind == "fnv64a") { - hash_value = fnv64a(data, file_size); - } else if (hash_kind == "murmur32") { - hash_value = gb_murmur32(data, file_size); - } else if (hash_kind == "murmur64") { - hash_value = gb_murmur64(data, file_size); - } else { - compiler_error("unhandled hash kind: %.*s", LIT(hash_kind)); + + if (!check_hash_kind(c, call, hash_kind, data, file_size, &hash_value)) { + return false; } string_map_set(&cache->hashes, hash_kind, hash_value); } @@ -1550,6 +1563,62 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o return true; } return false; + } else if (name == "hash") { + if (ce->args.count != 2) { + if (ce->args.count == 0) { + error(ce->close, "'#hash' expects 2 argument, got 0"); + } else { + error(ce->args[0], "'#hash' expects 2 argument, got %td", ce->args.count); + } + return false; + } + + Ast *arg0 = ce->args[0]; + Ast *arg1 = ce->args[1]; + Operand o = {}; + check_expr(c, &o, arg0); + if (o.mode != Addressing_Constant) { + error(arg0, "'#hash' expected a constant string argument"); + return false; + } + + if (!is_type_string(o.type)) { + gbString str = type_to_string(o.type); + error(arg0, "'#hash' expected a constant string, got %s", str); + gb_string_free(str); + return false; + } + + Operand o_hash = {}; + check_expr(c, &o_hash, arg1); + if (o_hash.mode != Addressing_Constant) { + error(arg1, "'#hash' expected a constant string argument"); + return false; + } + + if (!is_type_string(o_hash.type)) { + gbString str = type_to_string(o.type); + error(arg1, "'#hash' expected a constant string, got %s", str); + gb_string_free(str); + return false; + } + gbAllocator a = heap_allocator(); + + GB_ASSERT(o.value.kind == ExactValue_String); + GB_ASSERT(o_hash.value.kind == ExactValue_String); + + String original_string = o.value.value_string; + String hash_kind = o_hash.value.value_string; + + // TODO: Cache hash values based off of string constant and hash kind? + u64 hash_value = 0; + if (check_hash_kind(c, call, hash_kind, original_string.text, original_string.len, &hash_value)) { + operand->type = t_untyped_integer; + operand->mode = Addressing_Constant; + operand->value = exact_value_u64(hash_value); + return true; + } + return false; } else if (name == "assert") { if (ce->args.count != 1 && ce->args.count != 2) { error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8672941c1..2e008fe93 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7414,7 +7414,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c name == "config" || name == "load" || name == "load_directory" || - name == "load_hash" + name == "load_hash" || + name == "hash" ) { operand->mode = Addressing_Builtin; operand->builtin_id = BuiltinProc_DIRECTIVE; -- cgit v1.2.3 From 4f5b2bd12736b32c0a35496e8ca8f03d305c54b4 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 4 Jun 2024 19:01:50 +0200 Subject: fix crash when you have 2 `#load_directory` calls with the same path --- src/check_builtin.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index aa3be0bbd..15c63905e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1345,6 +1345,8 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c map_set(&c->info->load_directory_map, call, new_cache); } else { cache->file_error = file_error; + + map_set(&c->info->load_directory_map, call, cache); } }); -- cgit v1.2.3 From b47a15733df5d0cb858a2be0d4eb334df3d50536 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 4 Jun 2024 19:06:13 +0200 Subject: implement `#exists(path)` --- src/check_builtin.cpp | 94 ++++++++++++++++++++++++++++++++++++++------------- src/check_expr.cpp | 1 + src/checker.hpp | 9 +++++ 3 files changed, 80 insertions(+), 24 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 15c63905e..7e3bcb7ee 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1079,7 +1079,7 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return false; } -gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_) { +gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_, LoadFileTier tier) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); String builtin_name = bd->name.string; @@ -1105,12 +1105,16 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String gbFileError file_error = gbFileError_None; String data = {}; + bool exists = false; + LoadFileTier cache_tier = LoadFileTier_Invalid; LoadFileCache **cache_ptr = string_map_get(&c->info->load_file_cache, path); LoadFileCache *cache = cache_ptr ? *cache_ptr : nullptr; if (cache) { file_error = cache->file_error; data = cache->data; + exists = cache->exists; + cache_tier = cache->tier; } defer ({ if (cache == nullptr) { @@ -1118,60 +1122,78 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String new_cache->path = path; new_cache->data = data; new_cache->file_error = file_error; + new_cache->exists = exists; + new_cache->tier = cache_tier; string_map_init(&new_cache->hashes, 32); string_map_set(&c->info->load_file_cache, path, new_cache); if (cache_) *cache_ = new_cache; } else { cache->data = data; cache->file_error = file_error; + cache->exists = exists; + cache->tier = cache_tier; if (cache_) *cache_ = cache; } }); - TEMPORARY_ALLOCATOR_GUARD(); - char *c_str = alloc_cstring(temporary_allocator(), path); + if (tier > cache_tier) { + cache_tier = tier; - gbFile f = {}; - if (cache == nullptr) { + TEMPORARY_ALLOCATOR_GUARD(); + char *c_str = alloc_cstring(temporary_allocator(), path); + + gbFile f = {}; file_error = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + if (file_error == gbFileError_None) { + exists = true; + + switch(tier) { + case LoadFileTier_Exists: + // Nothing to do. + break; + case LoadFileTier_Contents: { + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *ptr = cast(u8 *)gb_alloc(permanent_allocator(), file_size+1); + gb_file_read_at(&f, ptr, file_size, 0); + ptr[file_size] = '\0'; + data.text = ptr; + data.len = file_size; + } + break; + } + default: + GB_PANIC("Unhandled LoadFileTier"); + }; + } } - defer (gb_file_close(&f)); switch (file_error) { default: case gbFileError_Invalid: if (err_on_not_found) { - error(ce->proc, "Failed to `#%.*s` file: %s; invalid file or cannot be found", LIT(builtin_name), c_str); + error(ce->proc, "Failed to `#%.*s` file: %.*s; invalid file or cannot be found", LIT(builtin_name), LIT(path)); } call->state_flags |= StateFlag_DirectiveWasFalse; return false; case gbFileError_NotExists: if (err_on_not_found) { - error(ce->proc, "Failed to `#%.*s` file: %s; file cannot be found", LIT(builtin_name), c_str); + error(ce->proc, "Failed to `#%.*s` file: %.*s; file cannot be found", LIT(builtin_name), LIT(path)); } call->state_flags |= StateFlag_DirectiveWasFalse; return false; case gbFileError_Permission: if (err_on_not_found) { - error(ce->proc, "Failed to `#%.*s` file: %s; file permissions problem", LIT(builtin_name), c_str); + error(ce->proc, "Failed to `#%.*s` file: %.*s; file permissions problem", LIT(builtin_name), LIT(path)); } call->state_flags |= StateFlag_DirectiveWasFalse; return false; case gbFileError_None: // Okay break; - } - - if (cache == nullptr) { - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *ptr = cast(u8 *)gb_alloc(permanent_allocator(), file_size+1); - gb_file_read_at(&f, ptr, file_size, 0); - ptr[file_size] = '\0'; - data.text = ptr; - data.len = file_size; - } - } + }; return true; } @@ -1263,7 +1285,7 @@ gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand operand->mode = Addressing_Constant; LoadFileCache *cache = nullptr; - if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache)) { + if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache, LoadFileTier_Contents)) { operand->value = exact_value_string(cache->data); return LoadDirective_Success; } @@ -1391,7 +1413,7 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c for (FileInfo fi : list) { LoadFileCache *cache = nullptr; - if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache)) { + if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache, LoadFileTier_Contents)) { array_add(&file_caches, cache); } else { result = LoadDirective_Error; @@ -1490,6 +1512,30 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o operand->type = t_source_code_location; operand->mode = Addressing_Value; + } else if (name == "exists") { + if (ce->args.count != 1) { + error(ce->close, "'#exists' expects 1 argument, got %td", ce->args.count); + return false; + } + + Operand o = {}; + check_expr(c, &o, ce->args[0]); + if (o.mode != Addressing_Constant || !is_type_string(o.type)) { + error(ce->args[0], "'#exists' expected a constant string argument"); + return false; + } + + operand->type = t_untyped_bool; + operand->mode = Addressing_Constant; + + String original_string = o.value.value_string; + LoadFileCache *cache = nullptr; + if (cache_load_file_directive(c, call, original_string, /* err_on_not_found=*/ false, &cache, LoadFileTier_Exists)) { + operand->value = exact_value_bool(cache->exists); + } else { + operand->value = exact_value_bool(false); + } + } else if (name == "load") { return check_load_directive(c, operand, call, type_hint, true) == LoadDirective_Success; } else if (name == "load_directory") { @@ -1542,7 +1588,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o String hash_kind = o_hash.value.value_string; LoadFileCache *cache = nullptr; - if (cache_load_file_directive(c, call, original_string, true, &cache)) { + if (cache_load_file_directive(c, call, original_string, true, &cache, LoadFileTier_Contents)) { MUTEX_GUARD(&c->info->load_file_mutex); // TODO(bill): make these procedures fast :P u64 hash_value = 0; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2e008fe93..3bf2af24a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7408,6 +7408,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c String name = bd->name.string; if ( name == "location" || + name == "exists" || name == "assert" || name == "panic" || name == "defined" || diff --git a/src/checker.hpp b/src/checker.hpp index 539b72b2d..e793540e3 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -336,7 +336,16 @@ struct ObjcMsgData { ObjcMsgKind kind; Type *proc_type; }; + +enum LoadFileTier { + LoadFileTier_Invalid, + LoadFileTier_Exists, + LoadFileTier_Contents, +}; + struct LoadFileCache { + LoadFileTier tier; + bool exists; String path; gbFileError file_error; String data; -- cgit v1.2.3 From 9a95049393ea98ef6222bf217ab44dd127c3f960 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Mon, 22 Jan 2024 17:21:52 +0100 Subject: -show-defineables and -export-defineables --- src/build_settings.cpp | 2 + src/check_builtin.cpp | 11 ++++- src/checker.cpp | 2 + src/checker.hpp | 12 +++++ src/main.cpp | 124 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 251dd06dd..d25d553a9 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -844,6 +844,8 @@ struct BuildContext { bool show_unused; bool show_unused_with_location; bool show_more_timings; + bool show_defineables; + String export_defineables_file; bool show_system_calls; bool keep_temp_files; bool ignore_unknown_attributes; diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 7e3bcb7ee..b2afa3d0c 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1777,7 +1777,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o } String name = arg->Ident.token.string; - + operand->type = def.type; operand->mode = def.mode; @@ -1793,6 +1793,15 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o operand->value = found->Constant.value; } } + + Defineable defineable = {}; + defineable.name = name; + defineable.default_value = def.value; + defineable.pos = arg->Ident.token.pos; + + MUTEX_GUARD(&c->info->defineables_mutex); + array_add(&c->info->defineables, defineable); + } else { error(call, "Unknown directive call: #%.*s", LIT(name)); } diff --git a/src/checker.cpp b/src/checker.cpp index 8a58bb425..0f23e308b 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1275,6 +1275,7 @@ gb_internal void init_checker_info(CheckerInfo *i) { array_init(&i->init_procedures, a, 0, 0); array_init(&i->fini_procedures, a, 0, 0); array_init(&i->required_foreign_imports_through_force, a, 0, 0); + array_init(&i->defineables, a); map_init(&i->objc_msgSend_types); string_map_init(&i->load_file_cache); @@ -1304,6 +1305,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { string_map_destroy(&i->packages); array_free(&i->variable_init_order); array_free(&i->required_foreign_imports_through_force); + array_free(&i->defineables); mpsc_destroy(&i->entity_queue); mpsc_destroy(&i->definition_queue); diff --git a/src/checker.hpp b/src/checker.hpp index 2ac4c8e7a..fc37f5769 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -376,6 +376,15 @@ struct GenTypesData { RecursiveMutex mutex; }; +struct Defineable { + String name; + ExactValue default_value; + TokenPos pos; + + String default_value_str; + String pos_str; +}; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; @@ -402,6 +411,9 @@ struct CheckerInfo { Array entities; Array required_foreign_imports_through_force; + BlockingMutex defineables_mutex; + Array defineables; + // Below are accessed within procedures RwMutex global_untyped_mutex; diff --git a/src/main.cpp b/src/main.cpp index 70def5802..a3e87fb6a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -288,6 +288,9 @@ enum BuildFlagKind { BuildFlag_NoThreadedChecker, BuildFlag_ShowDebugMessages, + BuildFlag_ShowDefineables, + BuildFlag_ExportDefineables, + BuildFlag_Vet, BuildFlag_VetShadowing, BuildFlag_VetUnused, @@ -483,6 +486,9 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_ShowDefineables, str_lit("show-defineables"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_ExportDefineables, str_lit("export-defineables"), BuildFlagParam_String, Command__does_check); + add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUnused, str_lit("vet-unused"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUnusedVariables, str_lit("vet-unused-variables"), BuildFlagParam_None, Command__does_check); @@ -814,6 +820,24 @@ gb_internal bool parse_build_flags(Array args) { break; } + case BuildFlag_ShowDefineables: { + GB_ASSERT(value.kind == ExactValue_Invalid); + build_context.show_defineables = true; + break; + } + case BuildFlag_ExportDefineables: { + GB_ASSERT(value.kind == ExactValue_String); + + String export_path = string_trim_whitespace(value.value_string); + if (is_build_flag_path_valid(export_path)) { + build_context.export_defineables_file = path_to_full_path(heap_allocator(), export_path); + } else { + gb_printf_err("Invalid -export-defineables path, got %.*s\n", LIT(export_path)); + bad_flags = true; + } + + break; + } case BuildFlag_ShowSystemCalls: { GB_ASSERT(value.kind == ExactValue_Invalid); build_context.show_system_calls = true; @@ -1553,6 +1577,84 @@ gb_internal void timings_export_all(Timings *t, Checker *c, bool timings_are_fin gb_printf("Done.\n"); } +gb_internal void temp_alloc_defineable_strings(Checker *c) { + for_array(i, c->info.defineables) { + Defineable *def = &c->info.defineables[i]; + def->default_value_str = make_string_c(write_exact_value_to_string(gb_string_make(temporary_allocator(), ""), def->default_value)); + def->pos_str = make_string_c(token_pos_to_string(def->pos)); + } +} + +gb_internal GB_COMPARE_PROC(defineables_cmp) { + Defineable *x = (Defineable *)a; + Defineable *y = (Defineable *)b; + + int cmp = 0; + + String x_file = get_file_path_string(x->pos.file_id); + String y_file = get_file_path_string(y->pos.file_id); + cmp = string_compare(x_file, y_file); + if (cmp) { + return cmp; + } + + return i32_cmp(x->pos.offset, y->pos.offset); +} + +gb_internal void sort_defineables(Checker *c) { + gb_sort_array(c->info.defineables.data, c->info.defineables.count, defineables_cmp); +} + +gb_internal void export_defineables(Checker *c, String path) { + gbFile f = {}; + gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, (char *)path.text); + if (err != gbFileError_None) { + gb_printf_err("Failed to export defineables to: %.*s\n", LIT(path)); + gb_exit(1); + return; + } else { + gb_printf("Exporting defineables to '%.*s'...\n", LIT(path)); + } + defer (gb_file_close(&f)); + + gb_fprintf(&f, "Defineable,Default Value,Location\n"); + for_array(i, c->info.defineables) { + Defineable *def = &c->info.defineables[i]; + gb_fprintf(&f,"%.*s,%.*s,%.*s\n", LIT(def->name), LIT(def->default_value_str), LIT(def->pos_str)); + } +} + +gb_internal void show_defineables(Checker *c) { + int max_name_len = strlen("Defineable"); + int max_default_len = strlen("Default Value"); + int max_pos_len = strlen("Location"); + + for_array(i, c->info.defineables) { + Defineable *def = &c->info.defineables[i]; + if (def->name.len > max_name_len) { + max_name_len = def->name.len; + } + + if (def->default_value_str.len > max_default_len) { + max_default_len = def->default_value_str.len; + } + + if (def->pos_str.len > max_pos_len) { + max_pos_len = def->pos_str.len; + } + } + + printf("%-*s - %-*s - %-*s\n", max_name_len, "Defineable", max_default_len, "Default Value", max_pos_len, "Location"); + + for_array(i, c->info.defineables) { + Defineable *def = &c->info.defineables[i]; + printf("%-*.*s - %-*.*s - %-*.*s\n", + max_name_len, LIT(def->name), + max_default_len, LIT(def->default_value_str), + max_pos_len, LIT(def->pos_str)); + } +} + gb_internal void show_timings(Checker *c, Timings *t) { Parser *p = c->parser; isize lines = p->total_line_count; @@ -1955,6 +2057,15 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Usage in code:"); print_usage_line(3, "#config(SPAM, default_value)"); print_usage_line(0, ""); + + print_usage_line(1, "-show-defineables"); + print_usage_line(2, "Shows an overview of all the #config usages in the project."); + print_usage_line(0, ""); + + print_usage_line(1, "-export-defineables:"); + print_usage_line(2, "Exports an overview of all the #config usages in CSV format to the given file path."); + print_usage_line(2, "Example: -export-defineables:defineables.csv"); + print_usage_line(0, ""); } if (build) { @@ -2960,6 +3071,19 @@ int main(int arg_count, char const **arg_ptr) { print_all_errors(); } + if (build_context.show_defineables || build_context.export_defineables_file != "") { + TEMPORARY_ALLOCATOR_GUARD(); + temp_alloc_defineable_strings(checker); + sort_defineables(checker); + + if (build_context.show_defineables) { + show_defineables(checker); + } + + if (build_context.export_defineables_file != "") { + export_defineables(checker, build_context.export_defineables_file); + } + } if (build_context.command_kind == Command_strip_semicolon) { return strip_semicolons(parser); -- cgit v1.2.3 From b818a7713175d882a7f8b345cee59bd19b0d1d47 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 25 Jan 2024 02:16:30 +0100 Subject: check if -define is actually used --- src/check_builtin.cpp | 15 +++++++++++++-- src/checker.hpp | 1 + src/main.cpp | 33 ++++++++++++++++++++++++++++----- 3 files changed, 42 insertions(+), 7 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b2afa3d0c..a74082fb2 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1756,6 +1756,17 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o operand->mode = Addressing_Constant; operand->value = exact_value_bool(is_defined); + // If the arg is a selector expression we don't add it, `-define` only allows identifiers. + if (arg->kind == Ast_Ident) { + Defineable defineable = {}; + defineable.name = arg->Ident.token.string; + defineable.default_value = exact_value_bool(false); + defineable.pos = arg->Ident.token.pos; + + MUTEX_GUARD(&c->info->defineables_mutex); + array_add(&c->info->defineables, defineable); + } + } else if (name == "config") { if (ce->args.count != 2) { error(call, "'#config' expects 2 argument, got %td", ce->args.count); @@ -1777,7 +1788,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o } String name = arg->Ident.token.string; - + operand->type = def.type; operand->mode = def.mode; @@ -1794,7 +1805,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o } } - Defineable defineable = {}; + Defineable defineable = {}; defineable.name = name; defineable.default_value = def.value; defineable.pos = arg->Ident.token.pos; diff --git a/src/checker.hpp b/src/checker.hpp index fc37f5769..9db5757e3 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -381,6 +381,7 @@ struct Defineable { ExactValue default_value; TokenPos pos; + // These strings are only computed from previous fields when defineables are being shown or exported. String default_value_str; String pos_str; }; diff --git a/src/main.cpp b/src/main.cpp index a3e87fb6a..eac1b7ed9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -822,9 +822,9 @@ gb_internal bool parse_build_flags(Array args) { } case BuildFlag_ShowDefineables: { GB_ASSERT(value.kind == ExactValue_Invalid); - build_context.show_defineables = true; - break; - } + build_context.show_defineables = true; + break; + } case BuildFlag_ExportDefineables: { GB_ASSERT(value.kind == ExactValue_String); @@ -1577,6 +1577,28 @@ gb_internal void timings_export_all(Timings *t, Checker *c, bool timings_are_fin gb_printf("Done.\n"); } +gb_internal void check_defines(BuildContext *bc, Checker *c) { + for (auto const &entry : bc->defined_values) { + String name = make_string_c(entry.key); + ExactValue value = entry.value; + GB_ASSERT(value.kind != ExactValue_Invalid); + + bool found = false; + for_array(i, c->info.defineables) { + Defineable *def = &c->info.defineables[i]; + if (def->name == name) { + found = true; + break; + } + } + + if (!found) { + warning(nullptr, "given -define:%s is unused in the project", name); + error_line("\tSuggestion: use the -show-defineables flag for an overview of the possible defines\n"); + } + } +} + gb_internal void temp_alloc_defineable_strings(Checker *c) { for_array(i, c->info.defineables) { Defineable *def = &c->info.defineables[i]; @@ -2059,11 +2081,11 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-show-defineables"); - print_usage_line(2, "Shows an overview of all the #config usages in the project."); + print_usage_line(2, "Shows an overview of all the #config/#defined usages in the project."); print_usage_line(0, ""); print_usage_line(1, "-export-defineables:"); - print_usage_line(2, "Exports an overview of all the #config usages in CSV format to the given file path."); + print_usage_line(2, "Exports an overview of all the #config/#defined usages in CSV format to the given file path."); print_usage_line(2, "Example: -export-defineables:defineables.csv"); print_usage_line(0, ""); } @@ -3063,6 +3085,7 @@ int main(int arg_count, char const **arg_ptr) { defer (destroy_checker(checker)); check_parsed_files(checker); + check_defines(&build_context, checker); if (any_errors()) { print_all_errors(); return 1; -- cgit v1.2.3 From 7044a7d77650e922a66f3bfe99711f3ed370e1ba Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 6 Jun 2024 23:55:48 +0100 Subject: Try to fix a possible race condition with polymorphic record parameters --- src/check_builtin.cpp | 31 ++++++++----------------------- src/check_expr.cpp | 11 +++-------- src/check_type.cpp | 30 +++++++++++++----------------- src/checker.cpp | 4 ++++ src/types.cpp | 18 ++++++++++++++++++ 5 files changed, 46 insertions(+), 48 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 7e3bcb7ee..eef925d94 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5912,15 +5912,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a record type for '%.*s'", LIT(builtin_name)); } else { - Type *bt = base_type(operand->type); - if (bt->kind == Type_Struct) { - if (bt->Struct.polymorphic_params != nullptr) { - operand->value = exact_value_i64(bt->Struct.polymorphic_params->Tuple.variables.count); - } - } else if (bt->kind == Type_Union) { - if (bt->Union.polymorphic_params != nullptr) { - operand->value = exact_value_i64(bt->Union.polymorphic_params->Tuple.variables.count); - } + TypeTuple *tuple = get_record_polymorphic_params(operand->type); + if (tuple) { + operand->value = exact_value_i64(tuple->variables.count); } else { error(operand->expr, "Expected a record type for '%.*s'", LIT(builtin_name)); } @@ -5952,20 +5946,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Entity *param = nullptr; i64 count = 0; - Type *bt = base_type(operand->type); - if (bt->kind == Type_Struct) { - if (bt->Struct.polymorphic_params != nullptr) { - count = bt->Struct.polymorphic_params->Tuple.variables.count; - if (index < count) { - param = bt->Struct.polymorphic_params->Tuple.variables[cast(isize)index]; - } - } - } else if (bt->kind == Type_Union) { - if (bt->Union.polymorphic_params != nullptr) { - count = bt->Union.polymorphic_params->Tuple.variables.count; - if (index < count) { - param = bt->Union.polymorphic_params->Tuple.variables[cast(isize)index]; - } + TypeTuple *tuple = get_record_polymorphic_params(operand->type); + if (tuple) { + count = tuple->variables.count; + if (index < count) { + param = tuple->variables[cast(isize)index]; } } else { error(operand->expr, "Expected a specialized polymorphic record type for '%.*s'", LIT(builtin_name)); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d2d01deda..ad546858c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7331,14 +7331,9 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O gbString s = gb_string_make_reserve(heap_allocator(), e->token.string.len+3); s = gb_string_append_fmt(s, "%.*s(", LIT(e->token.string)); - Type *params = nullptr; - switch (bt->kind) { - case Type_Struct: params = bt->Struct.polymorphic_params; break; - case Type_Union: params = bt->Union.polymorphic_params; break; - } - - if (params != nullptr) for_array(i, params->Tuple.variables) { - Entity *v = params->Tuple.variables[i]; + TypeTuple *tuple = get_record_polymorphic_params(e->type); + if (tuple != nullptr) for_array(i, tuple->variables) { + Entity *v = tuple->variables[i]; String name = v->token.string; if (i > 0) { s = gb_string_append_fmt(s, ", "); diff --git a/src/check_type.cpp b/src/check_type.cpp index 7ed657bee..e0dea19cb 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -564,19 +564,7 @@ gb_internal bool check_record_poly_operand_specialization(CheckerContext *ctx, T gb_internal Entity *find_polymorphic_record_entity(GenTypesData *found_gen_types, isize param_count, Array const &ordered_operands) { for (Entity *e : found_gen_types->types) { Type *t = base_type(e->type); - TypeTuple *tuple = nullptr; - switch (t->kind) { - case Type_Struct: - if (t->Struct.polymorphic_params) { - tuple = &t->Struct.polymorphic_params->Tuple; - } - break; - case Type_Union: - if (t->Union.polymorphic_params) { - tuple = &t->Union.polymorphic_params->Tuple; - } - break; - } + TypeTuple *tuple = get_record_polymorphic_params(t); GB_ASSERT_MSG(tuple != nullptr, "%s :: %s", type_to_string(e->type), type_to_string(t)); GB_ASSERT(param_count == tuple->variables.count); @@ -663,6 +651,8 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast * &struct_type->Struct.is_polymorphic, node, poly_operands ); + wait_signal_set(&struct_type->Struct.polymorphic_wait_signal); + struct_type->Struct.is_poly_specialized = check_record_poly_operand_specialization(ctx, struct_type, poly_operands, &struct_type->Struct.is_polymorphic); if (original_type_for_poly) { GB_ASSERT(named_type != nullptr); @@ -712,6 +702,8 @@ gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *no &union_type->Union.is_polymorphic, node, poly_operands ); + wait_signal_set(&union_type->Union.polymorphic_wait_signal); + union_type->Union.is_poly_specialized = check_record_poly_operand_specialization(ctx, union_type, poly_operands, &union_type->Union.is_polymorphic); if (original_type_for_poly) { GB_ASSERT(named_type != nullptr); @@ -1453,12 +1445,14 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special return true; } + wait_for_record_polymorphic_params(s); + wait_for_record_polymorphic_params(t); if (t->Struct.polymorphic_parent == s->Struct.polymorphic_parent && s->Struct.polymorphic_params != nullptr && t->Struct.polymorphic_params != nullptr) { - TypeTuple *s_tuple = &s->Struct.polymorphic_params->Tuple; - TypeTuple *t_tuple = &t->Struct.polymorphic_params->Tuple; + TypeTuple *s_tuple = get_record_polymorphic_params(s); + TypeTuple *t_tuple = get_record_polymorphic_params(t); GB_ASSERT(t_tuple->variables.count == s_tuple->variables.count); for_array(i, s_tuple->variables) { Entity *s_e = s_tuple->variables[i]; @@ -1506,12 +1500,14 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special return true; } + wait_for_record_polymorphic_params(s); + wait_for_record_polymorphic_params(t); if (t->Union.polymorphic_parent == s->Union.polymorphic_parent && s->Union.polymorphic_params != nullptr && t->Union.polymorphic_params != nullptr) { - TypeTuple *s_tuple = &s->Union.polymorphic_params->Tuple; - TypeTuple *t_tuple = &t->Union.polymorphic_params->Tuple; + TypeTuple *s_tuple = get_record_polymorphic_params(s); + TypeTuple *t_tuple = get_record_polymorphic_params(t); GB_ASSERT(t_tuple->variables.count == s_tuple->variables.count); for_array(i, s_tuple->variables) { Entity *s_e = s_tuple->variables[i]; diff --git a/src/checker.cpp b/src/checker.cpp index 8a58bb425..e90509c1f 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2031,6 +2031,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { } else { add_type_info_type_internal(c, t_type_info_ptr); } + wait_for_record_polymorphic_params(bt); add_type_info_type_internal(c, bt->Union.polymorphic_params); for_array(i, bt->Union.variants) { add_type_info_type_internal(c, bt->Union.variants[i]); @@ -2063,6 +2064,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { } } } + wait_for_record_polymorphic_params(bt); add_type_info_type_internal(c, bt->Struct.polymorphic_params); for_array(i, bt->Struct.fields) { Entity *f = bt->Struct.fields[i]; @@ -2292,6 +2294,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { } else { add_min_dep_type_info(c, t_type_info_ptr); } + wait_for_record_polymorphic_params(bt); add_min_dep_type_info(c, bt->Union.polymorphic_params); for_array(i, bt->Union.variants) { add_min_dep_type_info(c, bt->Union.variants[i]); @@ -2321,6 +2324,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { } } } + wait_for_record_polymorphic_params(bt); add_min_dep_type_info(c, bt->Struct.polymorphic_params); for_array(i, bt->Struct.fields) { Entity *f = bt->Struct.fields[i]; diff --git a/src/types.cpp b/src/types.cpp index 45aa26894..4ceba5244 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -140,6 +140,7 @@ struct TypeStruct { i64 custom_field_align; Type * polymorphic_params; // Type_Tuple Type * polymorphic_parent; + Wait_Signal polymorphic_wait_signal; Type * soa_elem; i32 soa_count; @@ -167,6 +168,7 @@ struct TypeUnion { i64 custom_align; Type * polymorphic_params; // Type_Tuple Type * polymorphic_parent; + Wait_Signal polymorphic_wait_signal; i16 tag_size; bool is_polymorphic; @@ -1093,6 +1095,7 @@ gb_internal Type *alloc_type_struct() { gb_internal Type *alloc_type_struct_complete() { Type *t = alloc_type(Type_Struct); wait_signal_set(&t->Struct.fields_wait_signal); + wait_signal_set(&t->Struct.polymorphic_wait_signal); return t; } @@ -2136,15 +2139,30 @@ gb_internal bool is_type_polymorphic_record_unspecialized(Type *t) { return false; } +gb_internal void wait_for_record_polymorphic_params(Type *t) { + t = base_type(t); + switch (t->kind) { + case Type_Struct: + wait_signal_until_available(&t->Struct.polymorphic_wait_signal); + break; + case Type_Union: + wait_signal_until_available(&t->Union.polymorphic_wait_signal); + break; + } +} + + gb_internal TypeTuple *get_record_polymorphic_params(Type *t) { t = base_type(t); switch (t->kind) { case Type_Struct: + wait_signal_until_available(&t->Struct.polymorphic_wait_signal); if (t->Struct.polymorphic_params) { return &t->Struct.polymorphic_params->Tuple; } break; case Type_Union: + wait_signal_until_available(&t->Union.polymorphic_wait_signal); if (t->Union.polymorphic_params) { return &t->Union.polymorphic_params->Tuple; } -- cgit v1.2.3 From 315695b4f8b3437fb63cfc99c976b76be4cee173 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Fri, 7 Jun 2024 14:48:11 +0200 Subject: collect and show docs of defineables --- src/check_builtin.cpp | 8 ++++++- src/checker.hpp | 7 +++--- src/main.cpp | 62 ++++++++++++++++++++++++++++----------------------- 3 files changed, 45 insertions(+), 32 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index a74082fb2..54708b5ae 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1759,6 +1759,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o // If the arg is a selector expression we don't add it, `-define` only allows identifiers. if (arg->kind == Ast_Ident) { Defineable defineable = {}; + defineable.docs = nullptr; defineable.name = arg->Ident.token.string; defineable.default_value = exact_value_bool(false); defineable.pos = arg->Ident.token.pos; @@ -1769,7 +1770,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o } else if (name == "config") { if (ce->args.count != 2) { - error(call, "'#config' expects 2 argument, got %td", ce->args.count); + error(call, "'#config' expects 2 arguments, got %td", ce->args.count); return false; } Ast *arg = unparen_expr(ce->args[0]); @@ -1806,10 +1807,15 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o } Defineable defineable = {}; + defineable.docs = nullptr; defineable.name = name; defineable.default_value = def.value; defineable.pos = arg->Ident.token.pos; + if (c->decl) { + defineable.docs = c->decl->docs; + } + MUTEX_GUARD(&c->info->defineables_mutex); array_add(&c->info->defineables, defineable); diff --git a/src/checker.hpp b/src/checker.hpp index 9db5757e3..1a8cef29a 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -377,9 +377,10 @@ struct GenTypesData { }; struct Defineable { - String name; - ExactValue default_value; - TokenPos pos; + String name; + ExactValue default_value; + TokenPos pos; + CommentGroup *docs; // These strings are only computed from previous fields when defineables are being shown or exported. String default_value_str; diff --git a/src/main.cpp b/src/main.cpp index 793030f3f..530681d03 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1593,7 +1593,8 @@ gb_internal void check_defines(BuildContext *bc, Checker *c) { } if (!found) { - warning(nullptr, "given -define:%s is unused in the project", name); + ERROR_BLOCK(); + warning(nullptr, "given -define:%.*s is unused in the project", LIT(name)); error_line("\tSuggestion: use the -show-defineables flag for an overview of the possible defines\n"); } } @@ -1639,44 +1640,49 @@ gb_internal void export_defineables(Checker *c, String path) { } defer (gb_file_close(&f)); - gb_fprintf(&f, "Defineable,Default Value,Location\n"); + gbString docs = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(docs)); + + gb_fprintf(&f, "Defineable,Default Value,Docs,Location\n"); for_array(i, c->info.defineables) { Defineable *def = &c->info.defineables[i]; - gb_fprintf(&f,"%.*s,%.*s,%.*s\n", LIT(def->name), LIT(def->default_value_str), LIT(def->pos_str)); + + gb_string_clear(docs); + if (def->docs) { + docs = gb_string_appendc(docs, "\""); + for (Token const &token : def->docs->list) { + for (isize i = 0; i < token.string.len; i++) { + u8 c = token.string.text[i]; + if (c == '"') { + docs = gb_string_appendc(docs, "\"\""); + } else { + docs = gb_string_append_length(docs, &c, 1); + } + } + } + docs = gb_string_appendc(docs, "\""); + } + + gb_fprintf(&f,"%.*s,%.*s,%s,%.*s\n", LIT(def->name), LIT(def->default_value_str), docs, LIT(def->pos_str)); } } gb_internal void show_defineables(Checker *c) { - isize max_name_len = gb_strlen("Defineable"); - isize max_default_len = gb_strlen("Default Value"); - isize max_pos_len = gb_strlen("Location"); - for_array(i, c->info.defineables) { Defineable *def = &c->info.defineables[i]; - if (def->name.len > max_name_len) { - max_name_len = def->name.len; + if (has_ansi_terminal_colours()) { + gb_printf("\x1b[0;90m"); } - - if (def->default_value_str.len > max_default_len) { - max_default_len = def->default_value_str.len; + printf("%.*s\n", LIT(def->pos_str)); + if (def->docs) { + for (Token const &token : def->docs->list) { + gb_printf("%.*s\n", LIT(token.string)); + } } - - if (def->pos_str.len > max_pos_len) { - max_pos_len = def->pos_str.len; + if (has_ansi_terminal_colours()) { + gb_printf("\x1b[0m"); } - } - - printf("%-*s - %-*s - %-*s\n", - cast(int)max_name_len, "Defineable", - cast(int)max_default_len, "Default Value", - cast(int)max_pos_len, "Location"); - - for_array(i, c->info.defineables) { - Defineable *def = &c->info.defineables[i]; - printf("%-*.*s - %-*.*s - %-*.*s\n", - cast(int)max_name_len, LIT(def->name), - cast(int)max_default_len, LIT(def->default_value_str), - cast(int)max_pos_len, LIT(def->pos_str)); + gb_printf("%.*s :: %.*s\n\n", LIT(def->name), LIT(def->default_value_str)); } } -- cgit v1.2.3 From 49f147cc86d06ee60dd6936404b18f952196d9a8 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 8 Jun 2024 17:05:00 -0400 Subject: Prevent panic when `swizzle` called with < 2 indices The requirement for at least 2 indices has been sourced from `lb_addr_swizzle` in `llvm_backend_general.cpp`, where there is an assert to ensure the swizzle_count is `1 < n <= 4`. --- src/check_builtin.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index eef925d94..98c695a2c 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2419,6 +2419,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (arg_count > max_count) { error(call, "Too many 'swizzle' indices, %td > %td", arg_count, max_count); return false; + } else if (arg_count < 2) { + error(call, "Not enough 'swizzle' indices, %td < 2", arg_count); + return false; } if (type->kind == Type_Array) { -- cgit v1.2.3 From fa3cae2bb04db76f52f1b2288a9c858f20332b8a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 10 Jun 2024 15:02:34 +0100 Subject: Add `intrinsics.procedure_of` ```odin foo :: proc(x: $T) { fmt.println(x) } bar :: intrinsics.procedure_of(foo(int(123))) // parameters are never ran at compile time, similar to `size_of` bar(333) // prints 333 ``` --- base/intrinsics/intrinsics.odin | 4 ++++ src/check_builtin.cpp | 46 +++++++++++++++++++++++++++++++++++++++++ src/check_decl.cpp | 17 ++++++++++----- src/check_expr.cpp | 1 + src/check_stmt.cpp | 10 ++++++++- src/checker.cpp | 4 ++++ src/checker.hpp | 6 ++++++ src/checker_builtin_procs.hpp | 4 ++++ src/parser.hpp | 1 + 9 files changed, 87 insertions(+), 6 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 8873f3bbc..4f6fa2713 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -295,6 +295,10 @@ simd_rotate_right :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T --- // if all listed features are supported. has_target_feature :: proc($test: $T) -> bool where type_is_string(T) || type_is_proc(T) --- + +// Returns the value of the procedure where `x` must be a call expression +procedure_of :: proc(x: $T) -> T where type_is_proc(T) --- + // WASM targets only wasm_memory_grow :: proc(index, delta: uintptr) -> int --- wasm_memory_size :: proc(index: uintptr) -> int --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 98c695a2c..3aee804df 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1843,6 +1843,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_objc_register_class: case BuiltinProc_atomic_type_is_lock_free: case BuiltinProc_has_target_feature: + case BuiltinProc_procedure_of: // NOTE(bill): The first arg may be a Type, this will be checked case by case break; @@ -6157,6 +6158,51 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } + case BuiltinProc_procedure_of: + { + Ast *call_expr = unparen_expr(ce->args[0]); + Operand op = {}; + check_expr_base(c, &op, ce->args[0], nullptr); + if (op.mode != Addressing_Value && !(call_expr && call_expr->kind == Ast_CallExpr)) { + error(ce->args[0], "Expected a call expression for '%.*s'", LIT(builtin_name)); + return false; + } + + Ast *proc = call_expr->CallExpr.proc; + Entity *e = entity_of_node(proc); + + if (e == nullptr) { + error(ce->args[0], "Invalid procedure value, expected a regular/specialized procedure"); + return false; + } + + TypeAndValue tav = proc->tav; + + + operand->type = e->type; + operand->mode = Addressing_Value; + operand->value = tav.value; + operand->builtin_id = BuiltinProc_Invalid; + operand->proc_group = nullptr; + + if (tav.mode == Addressing_Builtin) { + operand->mode = tav.mode; + operand->builtin_id = cast(BuiltinProcId)e->Builtin.id; + break; + } + + if (!is_type_proc(e->type)) { + gbString s = type_to_string(e->type); + error(ce->args[0], "Expected a procedure value, got '%s'", s); + gb_string_free(s); + return false; + } + + + ce->entity_procedure_of = e; + break; + } + case BuiltinProc_constant_utf16_cstring: { String value = {}; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 43947836b..13b14149a 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -88,11 +88,14 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o e->type = t_invalid; return nullptr; } else if (is_type_polymorphic(t)) { - gbString str = type_to_string(t); - defer (gb_string_free(str)); - error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name)); - e->type = t_invalid; - return nullptr; + Entity *e = entity_of_node(operand->expr); + if (e->state.load() != EntityState_Resolved) { + gbString str = type_to_string(t); + defer (gb_string_free(str)); + error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name)); + e->type = t_invalid; + return nullptr; + } } else if (is_type_empty_union(t)) { gbString str = type_to_string(t); defer (gb_string_free(str)); @@ -479,6 +482,9 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr entity = check_selector(ctx, &operand, init, e->type); } else { check_expr_or_type(ctx, &operand, init, e->type); + if (init->kind == Ast_CallExpr) { + entity = init->CallExpr.entity_procedure_of; + } } switch (operand.mode) { @@ -526,6 +532,7 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr return; } + if (entity != nullptr) { if (e->type != nullptr) { Operand x = {}; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 641f70566..01cba881e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -578,6 +578,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E d->defer_use_checked = false; Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags); + entity->state.store(EntityState_Resolved); entity->identifier = ident; add_entity_and_decl_info(&nctx, ident, entity, d); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index c37c58cd6..f2e3b0242 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -2224,8 +2224,16 @@ gb_internal void check_expr_stmt(CheckerContext *ctx, Ast *node) { } if (do_require) { gbString expr_str = expr_to_string(ce->proc); + defer (gb_string_free(expr_str)); + if (builtin_id) { + String real_name = builtin_procs[builtin_id].name; + if (real_name != make_string(cast(u8 const *)expr_str, gb_string_length(expr_str))) { + error(node, "'%s' ('%.*s.%.*s') requires that its results must be handled", expr_str, + LIT(builtin_proc_pkg_name[builtin_procs[builtin_id].pkg]), LIT(real_name)); + return; + } + } error(node, "'%s' requires that its results must be handled", expr_str); - gb_string_free(expr_str); } return; } else if (expr && expr->kind == Ast_SelectorCallExpr) { diff --git a/src/checker.cpp b/src/checker.cpp index 8f0cc1cd1..852fb89bb 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1479,6 +1479,10 @@ gb_internal Entity *entity_of_node(Ast *expr) { case_ast_node(cc, CaseClause, expr); return cc->implicit_entity; case_end; + + case_ast_node(ce, CallExpr, expr); + return ce->entity_procedure_of; + case_end; } return nullptr; } diff --git a/src/checker.hpp b/src/checker.hpp index 2ac4c8e7a..492a64fb6 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -51,6 +51,12 @@ enum StmtFlag { enum BuiltinProcPkg { BuiltinProcPkg_builtin, BuiltinProcPkg_intrinsics, + BuiltinProcPkg_COUNT +}; + +String builtin_proc_pkg_name[BuiltinProcPkg_COUNT] = { + str_lit("builtin"), + str_lit("intrinsics"), }; struct BuiltinProc { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 5f98bb7b3..35acad42f 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -299,6 +299,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc__type_end, + BuiltinProc_procedure_of, + BuiltinProc___entry_point, BuiltinProc_objc_send, @@ -614,6 +616,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("procedure_of"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("objc_send"), 3, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, diff --git a/src/parser.hpp b/src/parser.hpp index 0e411d9ac..02f2af28d 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -458,6 +458,7 @@ AST_KIND(_ExprBegin, "", bool) \ bool optional_ok_one; \ bool was_selector; \ AstSplitArgs *split_args; \ + Entity *entity_procedure_of; \ }) \ AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \ AST_KIND(EnumFieldValue, "enum field value", struct { \ -- cgit v1.2.3 From 5b5402fb23d0902810f18f805a72120f5243bddd Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 12 Jun 2024 13:07:13 -0400 Subject: Add `intrinsics.syscall_bsd` This is a BSD-style syscall that checks for a high Carry Flag as the error state. If the CF is high, the boolean return value is false, and if it is low (no errors) then the boolean return value is true. --- base/intrinsics/intrinsics.odin | 2 + core/sys/unix/sysctl_freebsd.odin | 7 +- src/check_builtin.cpp | 58 +++++++++++-- src/checker_builtin_procs.hpp | 4 +- src/llvm_backend_proc.cpp | 178 ++++++++++++++++++++++++++++---------- 5 files changed, 195 insertions(+), 54 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 4f6fa2713..635c85e6f 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -73,6 +73,8 @@ expect :: proc(val, expected_val: T) -> T --- // Linux and Darwin Only syscall :: proc(id: uintptr, args: ..uintptr) -> uintptr --- +// FreeBSD, NetBSD, et cetera +syscall_bsd :: proc(id: uintptr, args: ..uintptr) -> (uintptr, bool) --- // Atomics diff --git a/core/sys/unix/sysctl_freebsd.odin b/core/sys/unix/sysctl_freebsd.odin index d1acbc2a1..35c5db02c 100644 --- a/core/sys/unix/sysctl_freebsd.odin +++ b/core/sys/unix/sysctl_freebsd.odin @@ -5,14 +5,15 @@ import "base:intrinsics" sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) { mib := mib - result_size := i64(size_of(T)) + result_size := u64(size_of(T)) - res := intrinsics.syscall(SYS_sysctl, + res: uintptr + res, ok = intrinsics.syscall_bsd(SYS_sysctl, uintptr(raw_data(mib)), uintptr(len(mib)), uintptr(val), uintptr(&result_size), uintptr(0), uintptr(0), ) - return res == 0 + return } // See /usr/include/sys/sysctl.h for details diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 3aee804df..396a8bd80 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5089,15 +5089,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As isize max_arg_count = 32; switch (build_context.metrics.os) { - case TargetOs_windows: - case TargetOs_freestanding: - error(call, "'%.*s' is not supported on this platform (%.*s)", LIT(builtin_name), LIT(target_os_names[build_context.metrics.os])); - break; case TargetOs_darwin: case TargetOs_linux: case TargetOs_essence: - case TargetOs_freebsd: - case TargetOs_openbsd: case TargetOs_haiku: switch (build_context.metrics.arch) { case TargetArch_i386: @@ -5107,6 +5101,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } break; + default: + error(call, "'%.*s' is not supported on this platform (%.*s)", LIT(builtin_name), LIT(target_os_names[build_context.metrics.os])); + break; } if (ce->args.count > max_arg_count) { @@ -5120,6 +5117,55 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return true; } break; + case BuiltinProc_syscall_bsd: + { + convert_to_typed(c, operand, t_uintptr); + if (!is_type_uintptr(operand->type)) { + gbString t = type_to_string(operand->type); + error(operand->expr, "Argument 0 must be of type 'uintptr', got %s", t); + gb_string_free(t); + } + for (isize i = 1; i < ce->args.count; i++) { + Operand x = {}; + check_expr(c, &x, ce->args[i]); + if (x.mode != Addressing_Invalid) { + convert_to_typed(c, &x, t_uintptr); + } + convert_to_typed(c, &x, t_uintptr); + if (!is_type_uintptr(x.type)) { + gbString t = type_to_string(x.type); + error(x.expr, "Argument %td must be of type 'uintptr', got %s", i, t); + gb_string_free(t); + } + } + + isize max_arg_count = 32; + + switch (build_context.metrics.os) { + case TargetOs_freebsd: + case TargetOs_netbsd: + case TargetOs_openbsd: + switch (build_context.metrics.arch) { + case TargetArch_amd64: + case TargetArch_arm64: + max_arg_count = 7; + break; + } + break; + default: + error(call, "'%.*s' is not supported on this platform (%.*s)", LIT(builtin_name), LIT(target_os_names[build_context.metrics.os])); + break; + } + + if (ce->args.count > max_arg_count) { + error(ast_end_token(call), "'%.*s' has a maximum of %td arguments on this platform (%.*s), got %td", LIT(builtin_name), max_arg_count, LIT(target_os_names[build_context.metrics.os]), ce->args.count); + } + + operand->mode = Addressing_Value; + operand->type = make_optional_ok_type(t_uintptr); + return true; + } + break; case BuiltinProc_type_base_type: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 35acad42f..a2b8a5361 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -192,6 +192,7 @@ BuiltinProc__simd_end, // Platform specific intrinsics BuiltinProc_syscall, + BuiltinProc_syscall_bsd, BuiltinProc_x86_cpuid, BuiltinProc_x86_xgetbv, @@ -512,7 +513,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("syscall"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, + {STR_LIT("syscall"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, + {STR_LIT("syscall_bsd"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("x86_cpuid"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("x86_xgetbv"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 87f75fb1d..958b4fd38 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2747,26 +2747,10 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu { GB_ASSERT(arg_count <= 7); - // FreeBSD additionally clobbers r8, r9, r10, but they - // can also be used to pass in arguments, so this needs - // to be handled in two parts. - bool clobber_arg_regs[7] = { - false, false, false, false, false, false, false - }; - if (build_context.metrics.os == TargetOs_freebsd) { - clobber_arg_regs[4] = true; // r10 - clobber_arg_regs[5] = true; // r8 - clobber_arg_regs[6] = true; // r9 - } - char asm_string[] = "syscall"; gbString constraints = gb_string_make(heap_allocator(), "={rax}"); for (unsigned i = 0; i < arg_count; i++) { - if (!clobber_arg_regs[i]) { - constraints = gb_string_appendc(constraints, ",{"); - } else { - constraints = gb_string_appendc(constraints, ",+{"); - } + constraints = gb_string_appendc(constraints, ",{"); static char const *regs[] = { "rax", "rdi", @@ -2790,36 +2774,9 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu // Some but not all system calls will additionally // clobber memory. // - // As a fix for CVE-2019-5595, FreeBSD started - // clobbering R8, R9, and R10, instead of restoring - // them. Additionally unlike Linux, instead of - // returning negative errno, positive errno is - // returned and CF is set. - // // TODO: // * Figure out what Darwin does. - // * Add some extra handling to propagate CF back - // up to the caller on FreeBSD systems so that - // the caller knows that the return value is - // positive errno. constraints = gb_string_appendc(constraints, ",~{rcx},~{r11},~{memory}"); - if (build_context.metrics.os == TargetOs_freebsd) { - // Second half of dealing with FreeBSD's system - // call semantics. Explicitly clobber the registers - // that were not used to pass in arguments, and - // then clobber RFLAGS. - if (arg_count < 5) { - constraints = gb_string_appendc(constraints, ",~{r10}"); - } - if (arg_count < 6) { - constraints = gb_string_appendc(constraints, ",~{r8}"); - } - if (arg_count < 7) { - constraints = gb_string_appendc(constraints, ",~{r9}"); - } - constraints = gb_string_appendc(constraints, ",~{cc}"); - } - inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } break; @@ -2927,6 +2884,139 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu res.type = t_uintptr; return res; } + case BuiltinProc_syscall_bsd: + { + // This is a BSD-style syscall where errors are indicated by a high + // Carry Flag and a positive return value, allowing the kernel to + // return any value that fits into a machine word. + // + // This is unlike Linux, where errors are indicated by a negative + // return value, limiting what can be expressed in one result. + unsigned arg_count = cast(unsigned)ce->args.count; + LLVMValueRef *args = gb_alloc_array(permanent_allocator(), LLVMValueRef, arg_count); + for_array(i, ce->args) { + lbValue arg = lb_build_expr(p, ce->args[i]); + arg = lb_emit_conv(p, arg, t_uintptr); + args[i] = arg.value; + } + + LLVMTypeRef llvm_uintptr = lb_type(p->module, t_uintptr); + LLVMTypeRef *llvm_arg_types = gb_alloc_array(permanent_allocator(), LLVMTypeRef, arg_count); + for (unsigned i = 0; i < arg_count; i++) { + llvm_arg_types[i] = llvm_uintptr; + } + + LLVMTypeRef *results = gb_alloc_array(permanent_allocator(), LLVMTypeRef, 2); + results[0] = lb_type(p->module, t_uintptr); + results[1] = lb_type(p->module, t_bool); + LLVMTypeRef llvm_results = LLVMStructTypeInContext(p->module->ctx, results, 2, false); + + LLVMTypeRef func_type = LLVMFunctionType(llvm_results, llvm_arg_types, arg_count, false); + + LLVMValueRef inline_asm = nullptr; + + switch (build_context.metrics.arch) { + case TargetArch_amd64: + { + GB_ASSERT(arg_count <= 7); + + char asm_string[] = "syscall; setnb %cl"; + + // Using CL as an output; RCX doesn't need to get clobbered later. + gbString constraints = gb_string_make(heap_allocator(), "={rax},={cl}"); + for (unsigned i = 0; i < arg_count; i++) { + constraints = gb_string_appendc(constraints, ",{"); + static char const *regs[] = { + "rax", + "rdi", + "rsi", + "rdx", + "r10", + "r8", + "r9", + }; + constraints = gb_string_appendc(constraints, regs[i]); + constraints = gb_string_appendc(constraints, "}"); + } + + // NOTE(Feoramund): If you're experiencing instability + // regarding syscalls during optimized builds, it is + // possible that the ABI has changed for your platform, + // or I've missed a register clobber. + // + // Documentation on this topic is sparse, but I was able to + // determine what registers were being clobbered by adding + // dummy values to them, setting a breakpoint after the + // syscall, and checking the state of the registers afterwards. + // + // Be advised that manually stepping through a debugger may + // cause the kernel to not return via sysret, which will + // preserve register state that normally would've been + // otherwise clobbered. + // + // It is also possible that some syscalls clobber different registers. + + if (build_context.metrics.os == TargetOs_freebsd) { + // As a fix for CVE-2019-5595, FreeBSD started + // clobbering R8, R9, and R10, instead of restoring + // them. + // + // More info here: + // + // https://www.freebsd.org/security/advisories/FreeBSD-SA-19:01.syscall.asc + // https://github.com/freebsd/freebsd-src/blob/098dbd7ff7f3da9dda03802cdb2d8755f816eada/sys/amd64/amd64/exception.S#L605 + // https://stackoverflow.com/q/66878250 + constraints = gb_string_appendc(constraints, ",~{r8},~{r9},~{r10}"); + } + + // Both FreeBSD and NetBSD might clobber RDX. + // + // For NetBSD, it was clobbered during a call to sysctl. + // + // For FreeBSD, it's listed as "return value 2" in their + // AMD64 assembly, so there's no guarantee that it will persist. + constraints = gb_string_appendc(constraints, ",~{rdx},~{r11},~{cc},~{memory}"); + + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); + } + break; + case TargetArch_arm64: + { + GB_ASSERT(arg_count <= 7); + + char asm_string[] = "svc #0; cset x8, cc"; + gbString constraints = gb_string_make(heap_allocator(), "={x0},={x8}"); + for (unsigned i = 0; i < arg_count; i++) { + constraints = gb_string_appendc(constraints, ",{"); + static char const *regs[] = { + "x8", + "x0", + "x1", + "x2", + "x3", + "x4", + "x5", + }; + constraints = gb_string_appendc(constraints, regs[i]); + constraints = gb_string_appendc(constraints, "}"); + } + + // FreeBSD clobbered x1 on a call to sysctl. + constraints = gb_string_appendc(constraints, ",~{x1},~{cc},~{memory}"); + + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); + } + break; + default: + GB_PANIC("Unsupported platform"); + } + + lbValue res = {}; + res.value = LLVMBuildCall2(p->builder, func_type, inline_asm, args, arg_count, ""); + res.type = make_optional_ok_type(t_uintptr, true); + + return res; + } case BuiltinProc_objc_send: return lb_handle_objc_send(p, expr); -- cgit v1.2.3 From dab3c832e00a3186bddc79585d9ba7ee10d39eaf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Jun 2024 15:32:30 +0100 Subject: Add `#warning()` builtin compile time procedure --- core/odin/parser/parser.odin | 2 +- src/check_builtin.cpp | 20 ++++++++++++++++++++ src/parser.cpp | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 6b0aa2888..7edd509d0 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1438,7 +1438,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { case: error(p, stmt.pos, "#partial can only be applied to a switch statement") } return stmt - case "assert", "panic": + case "assert", "panic", "warning": bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(tag)) bd.tok = tok bd.name = name diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 47abd42cf..e85981911 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1714,6 +1714,26 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o operand->type = t_untyped_bool; operand->mode = Addressing_Constant; + } else if (name == "warning") { + ERROR_BLOCK(); + if (ce->args.count != 1) { + error(call, "'#warning' expects 1 argument, got %td", ce->args.count); + return false; + } + if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) { + gbString str = expr_to_string(ce->args[0]); + error(call, "'%s' is not a constant string", str); + gb_string_free(str); + return false; + } + warning(call, "%.*s", LIT(operand->value.value_string)); + if (c->proc_name != "") { + gbString str = type_to_string(c->curr_proc_sig); + error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); + gb_string_free(str); + } + operand->type = t_invalid; + operand->mode = Addressing_NoValue; } else if (name == "panic") { ERROR_BLOCK(); if (ce->args.count != 1) { diff --git a/src/parser.cpp b/src/parser.cpp index 0cd96f5b5..7383c3360 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5167,7 +5167,7 @@ gb_internal Ast *parse_stmt(AstFile *f) { break; } return s; - } else if (tag == "assert" || tag == "panic") { + } else if (tag == "assert" || tag == "panic" || tag == "warning") { Ast *t = ast_basic_directive(f, hash_token, name); Ast *stmt = ast_expr_stmt(f, parse_call_expr(f, t)); expect_semicolon(f); -- cgit v1.2.3 From c0987394840d63fae627c1623ea2661c31adc9b9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 25 Jun 2024 09:36:59 +0100 Subject: Remove `@(warning)` and `#warning(...)` --- core/odin/parser/parser.odin | 2 +- src/check_builtin.cpp | 20 -------------------- src/checker.cpp | 14 -------------- src/parser.cpp | 2 +- 4 files changed, 2 insertions(+), 36 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 7edd509d0..6b0aa2888 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -1438,7 +1438,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt { case: error(p, stmt.pos, "#partial can only be applied to a switch statement") } return stmt - case "assert", "panic", "warning": + case "assert", "panic": bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(tag)) bd.tok = tok bd.name = name diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index e85981911..47abd42cf 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1714,26 +1714,6 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o operand->type = t_untyped_bool; operand->mode = Addressing_Constant; - } else if (name == "warning") { - ERROR_BLOCK(); - if (ce->args.count != 1) { - error(call, "'#warning' expects 1 argument, got %td", ce->args.count); - return false; - } - if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) { - gbString str = expr_to_string(ce->args[0]); - error(call, "'%s' is not a constant string", str); - gb_string_free(str); - return false; - } - warning(call, "%.*s", LIT(operand->value.value_string)); - if (c->proc_name != "") { - gbString str = type_to_string(c->curr_proc_sig); - error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); - gb_string_free(str); - } - operand->type = t_invalid; - operand->mode = Addressing_NoValue; } else if (name == "panic") { ERROR_BLOCK(); if (ce->args.count != 1) { diff --git a/src/checker.cpp b/src/checker.cpp index 4945b3810..fdf5a8b7d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3493,20 +3493,6 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { error(elem, "Expected a string value for '%.*s'", LIT(name)); } return true; - } else if (name == "warning") { - ExactValue ev = check_decl_attribute_value(c, value); - - if (ev.kind == ExactValue_String) { - String msg = ev.value_string; - if (msg.len == 0) { - error(elem, "Warning message cannot be an empty string"); - } else { - ac->warning_message = msg; - } - } else { - error(elem, "Expected a string value for '%.*s'", LIT(name)); - } - return true; } else if (name == "require_results") { if (value != nullptr) { error(elem, "Expected no value for '%.*s'", LIT(name)); diff --git a/src/parser.cpp b/src/parser.cpp index 7383c3360..0cd96f5b5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5167,7 +5167,7 @@ gb_internal Ast *parse_stmt(AstFile *f) { break; } return s; - } else if (tag == "assert" || tag == "panic" || tag == "warning") { + } else if (tag == "assert" || tag == "panic") { Ast *t = ast_basic_directive(f, hash_token, name); Ast *stmt = ast_expr_stmt(f, parse_call_expr(f, t)); expect_semicolon(f); -- cgit v1.2.3 From d6b8544f508183871b636f8742ba813863d036f3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 29 Jun 2024 12:04:31 +0100 Subject: Add internal flag for testing stuff --- src/build_settings.cpp | 1 + src/check_builtin.cpp | 12 +++++++----- src/main.cpp | 5 +++++ 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index f9c426487..47a29a461 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -878,6 +878,7 @@ struct BuildContext { bool ignore_lazy; bool ignore_llvm_build; + bool ignore_panic; bool ignore_microsoft_magic; bool linker_map_file; diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 47abd42cf..c1422e80e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1726,11 +1726,13 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o gb_string_free(str); return false; } - error(call, "Compile time panic: %.*s", LIT(operand->value.value_string)); - if (c->proc_name != "") { - gbString str = type_to_string(c->curr_proc_sig); - error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); - gb_string_free(str); + if (!build_context.ignore_panic) { + error(call, "Compile time panic: %.*s", LIT(operand->value.value_string)); + if (c->proc_name != "") { + gbString str = type_to_string(c->curr_proc_sig); + error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); + gb_string_free(str); + } } operand->type = t_invalid; operand->mode = Addressing_NoValue; diff --git a/src/main.cpp b/src/main.cpp index 62aeccaf5..c1ec77ec4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -345,6 +345,7 @@ enum BuildFlagKind { // internal use only BuildFlag_InternalIgnoreLazy, BuildFlag_InternalIgnoreLLVMBuild, + BuildFlag_InternalIgnorePanic, BuildFlag_Tilde, @@ -543,6 +544,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalIgnorePanic, str_lit("internal-ignore-panic"), BuildFlagParam_None, Command_all); #if ALLOW_TILDE add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); @@ -1352,6 +1354,9 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_InternalIgnoreLLVMBuild: build_context.ignore_llvm_build = true; break; + case BuildFlag_InternalIgnorePanic: + build_context.ignore_panic = true; + break; case BuildFlag_Tilde: build_context.tilde_backend = true; break; -- cgit v1.2.3 From 544959326b467b6587a04d6211ea142de932109c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 1 Jul 2024 12:13:35 +0100 Subject: Add `intrinsics.type_struct_has_implicit_padding` #3844 --- base/intrinsics/intrinsics.odin | 3 ++- src/check_builtin.cpp | 25 +++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 4 +++- src/types.cpp | 1 + 4 files changed, 31 insertions(+), 2 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 635c85e6f..8a16ca40e 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -194,7 +194,8 @@ type_proc_return_count :: proc($T: typeid) -> int where type_is_proc(T) --- type_proc_parameter_type :: proc($T: typeid, index: int) -> typeid where type_is_proc(T) --- type_proc_return_type :: proc($T: typeid, index: int) -> typeid where type_is_proc(T) --- -type_struct_field_count :: proc($T: typeid) -> int where type_is_struct(T) --- +type_struct_field_count :: proc($T: typeid) -> int where type_is_struct(T) --- +type_struct_has_implicit_padding :: proc($T: typeid) -> bool where type_is_struct(T) --- type_polymorphic_record_parameter_count :: proc($T: typeid) -> typeid --- type_polymorphic_record_parameter_value :: proc($T: typeid, index: int) -> $V --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c1422e80e..7a1a8b9ee 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5839,6 +5839,31 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->mode = Addressing_Constant; operand->type = t_untyped_integer; break; + case BuiltinProc_type_struct_has_implicit_padding: + operand->value = exact_value_bool(false); + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a struct type for '%.*s'", LIT(builtin_name)); + } else if (!is_type_struct(operand->type) && !is_type_soa_struct(operand->type)) { + error(operand->expr, "Expected a struct type for '%.*s'", LIT(builtin_name)); + } else { + Type *bt = base_type(operand->type); + if (bt->Struct.is_packed) { + operand->value = exact_value_bool(false); + } else if (bt->Struct.fields.count != 0) { + i64 size = type_size_of(bt); + Type *field_type = nullptr; + i64 last_offset = type_offset_of(bt, bt->Struct.fields.count-1, &field_type); + if (last_offset+type_size_of(field_type) < size) { + operand->value = exact_value_bool(true); + } else { + i64 packed_size = type_size_of_struct_pretend_is_packed(bt); + operand->value = exact_value_bool(packed_size < size); + } + } + } + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + break; case BuiltinProc_type_proc_parameter_count: operand->value = exact_value_i64(0); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index a2b8a5361..a90c52e61 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -277,6 +277,7 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_bit_set_underlying_type, BuiltinProc_type_struct_field_count, + BuiltinProc_type_struct_has_implicit_padding, BuiltinProc_type_proc_parameter_count, BuiltinProc_type_proc_return_count, @@ -593,7 +594,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_bit_set_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_bit_set_underlying_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_struct_field_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_struct_has_implicit_padding"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_proc_parameter_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_proc_return_count"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/types.cpp b/src/types.cpp index 323c06580..c3a5fb539 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2366,6 +2366,7 @@ gb_internal bool type_has_nil(Type *t) { return false; } + gb_internal bool elem_type_can_be_constant(Type *t) { t = base_type(t); if (t == t_invalid) { -- cgit v1.2.3 From 782286357b2bc6a2f789b18744921b5b5b7b65c4 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Wed, 3 Jul 2024 22:21:32 +0200 Subject: error on type_of(value of untyped type) --- src/check_builtin.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 7a1a8b9ee..5a8d9b782 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2290,6 +2290,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As error(o.expr, "Invalid argument to 'type_of'"); return false; } + + if (is_type_untyped(o.type)) { + gbString t = type_to_string(o.type); + error(o.expr, "'type_of' of %s cannot be determined", t); + gb_string_free(t); + return false; + } + // NOTE(bill): Prevent type cycles for procedure declarations if (c->curr_proc_sig == o.type) { gbString s = expr_to_string(o.expr); -- cgit v1.2.3 From 48aef5016499291996f0710449a26f1f92078d51 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 8 Jul 2024 17:46:10 +0100 Subject: Add #load cache files to `-export-dependencies:json` --- src/check_builtin.cpp | 3 ++ src/main.cpp | 92 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 72 insertions(+), 23 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 5a8d9b782..eec01b497 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1296,6 +1296,9 @@ gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand gb_internal int file_cache_sort_cmp(void const *x, void const *y) { LoadFileCache const *a = *(LoadFileCache const **)(x); LoadFileCache const *b = *(LoadFileCache const **)(y); + if (a == b) { + return 0; + } return string_compare(a->path, b->path); } diff --git a/src/main.cpp b/src/main.cpp index 606b2b592..bbb326af3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1918,7 +1918,16 @@ gb_internal void show_timings(Checker *c, Timings *t) { } } -gb_internal void export_dependencies(Parser *p) { +gb_internal GB_COMPARE_PROC(file_path_cmp) { + AstFile *x = *(AstFile **)a; + AstFile *y = *(AstFile **)b; + if (x == y) { + return 0; + } + return string_compare(x->fullpath, y->fullpath); +} + +gb_internal void export_dependencies(Checker *c) { GB_ASSERT(build_context.export_dependencies_format != DependenciesExportUnspecified); if (build_context.export_dependencies_file.len <= 0) { @@ -1927,6 +1936,8 @@ gb_internal void export_dependencies(Parser *p) { return; } + Parser *p = c->parser; + gbFile f = {}; char * fileName = (char *)build_context.export_dependencies_file.text; gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, fileName); @@ -1937,6 +1948,26 @@ gb_internal void export_dependencies(Parser *p) { } defer (gb_file_close(&f)); + + auto files = array_make(heap_allocator()); + for (AstPackage *pkg : p->packages) { + for (AstFile *f : pkg->files) { + array_add(&files, f); + } + } + array_sort(files, file_path_cmp); + + + auto load_files = array_make(heap_allocator()); + for (auto const &entry : c->info.load_file_cache) { + auto *cache = entry.value; + if (!cache || !cache->exists) { + continue; + } + array_add(&load_files, cache); + } + array_sort(files, file_cache_sort_cmp); + if (build_context.export_dependencies_format == DependenciesExportMake) { String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); defer (gb_free(heap_allocator(), exe_name.text)); @@ -1945,26 +1976,25 @@ gb_internal void export_dependencies(Parser *p) { isize current_line_length = exe_name.len + 1; - for(AstPackage *pkg : p->packages) { - for(AstFile *file : pkg->files) { - /* Arbitrary line break value. Maybe make this better? */ - if (current_line_length >= 80-2) { - gb_file_write(&f, " \\\n ", 4); - current_line_length = 1; - } + for_array(i, files) { + AstFile *file = files[i]; + /* Arbitrary line break value. Maybe make this better? */ + if (current_line_length >= 80-2) { + gb_file_write(&f, " \\\n ", 4); + current_line_length = 1; + } - gb_file_write(&f, " ", 1); - current_line_length++; + gb_file_write(&f, " ", 1); + current_line_length++; - for (isize k = 0; k < file->fullpath.len; k++) { - char part = file->fullpath.text[k]; - if (part == ' ') { - gb_file_write(&f, "\\", 1); - current_line_length++; - } - gb_file_write(&f, &part, 1); + for (isize k = 0; k < file->fullpath.len; k++) { + char part = file->fullpath.text[k]; + if (part == ' ') { + gb_file_write(&f, "\\", 1); current_line_length++; } + gb_file_write(&f, &part, 1); + current_line_length++; } } @@ -1974,14 +2004,30 @@ gb_internal void export_dependencies(Parser *p) { gb_fprintf(&f, "\t\"source_files\": [\n"); - for(AstPackage *pkg : p->packages) { - for(AstFile *file : pkg->files) { - gb_fprintf(&f, "\t\t\"%.*s\",\n", LIT(file->fullpath)); + for_array(i, files) { + AstFile *file = files[i]; + gb_fprintf(&f, "\t\t\"%.*s\"", LIT(file->fullpath)); + if (i+1 == files.count) { + gb_fprintf(&f, ","); } + gb_fprintf(&f, "\n"); } gb_fprintf(&f, "\t],\n"); + gb_fprintf(&f, "\t\"load_files\": [\n"); + + for_array(i, load_files) { + LoadFileCache *cache = load_files[i]; + gb_fprintf(&f, "\t\t\"%.*s\"", LIT(cache->path)); + if (i+1 == load_files.count) { + gb_fprintf(&f, ","); + } + gb_fprintf(&f, "\n"); + } + + gb_fprintf(&f, "\t]\n"); + gb_fprintf(&f, "}\n"); } } @@ -3295,7 +3341,7 @@ int main(int arg_count, char const **arg_ptr) { } if (build_context.export_dependencies_format != DependenciesExportUnspecified) { - export_dependencies(parser); + export_dependencies(checker); } return result; } @@ -3326,7 +3372,7 @@ int main(int arg_count, char const **arg_ptr) { } if (build_context.export_dependencies_format != DependenciesExportUnspecified) { - export_dependencies(parser); + export_dependencies(checker); } return result; } @@ -3342,7 +3388,7 @@ int main(int arg_count, char const **arg_ptr) { } if (build_context.export_dependencies_format != DependenciesExportUnspecified) { - export_dependencies(parser); + export_dependencies(checker); } if (run_output) { -- cgit v1.2.3 From d87583beadaf94eacda3e4faf6293859cbdbc1e4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 15 Jul 2024 02:22:23 +0100 Subject: Minimize mutex lock for `#load_directory` --- src/check_builtin.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index eec01b497..db62b2bdb 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1079,7 +1079,7 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return false; } -gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_, LoadFileTier tier) { +gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_, LoadFileTier tier, bool use_mutex=true) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); String builtin_name = bd->name.string; @@ -1101,7 +1101,8 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String } } - MUTEX_GUARD(&c->info->load_file_mutex); + if (use_mutex) mutex_lock(&c->info->load_file_mutex); + defer (if (use_mutex) mutex_unlock(&c->info->load_file_mutex)); gbFileError file_error = gbFileError_None; String data = {}; @@ -1414,9 +1415,12 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c file_caches = array_make(heap_allocator(), 0, files_to_reserve); + mutex_lock(&c->info->load_file_mutex); + defer (mutex_unlock(&c->info->load_file_mutex)); + for (FileInfo fi : list) { LoadFileCache *cache = nullptr; - if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache, LoadFileTier_Contents)) { + if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache, LoadFileTier_Contents, /*use_mutex*/false)) { array_add(&file_caches, cache); } else { result = LoadDirective_Error; -- cgit v1.2.3 From 23ca27f40b956b03499e2095a04b252722e34bb6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Jul 2024 00:48:17 +0100 Subject: Add intrinsics `add_sat` and `sub_sat` --- src/check_builtin.cpp | 2 ++ src/checker_builtin_procs.hpp | 6 ++++++ src/llvm_backend_proc.cpp | 6 ++++++ 3 files changed, 14 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index db62b2bdb..26de3a112 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4261,6 +4261,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_overflow_add: case BuiltinProc_overflow_sub: case BuiltinProc_overflow_mul: + case BuiltinProc_add_sat: + case BuiltinProc_sub_sat: { Operand x = {}; Operand y = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index a90c52e61..3a2e1ce22 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -70,6 +70,9 @@ enum BuiltinProcId { BuiltinProc_overflow_sub, BuiltinProc_overflow_mul, + BuiltinProc_add_sat, + BuiltinProc_sub_sat, + BuiltinProc_sqrt, BuiltinProc_fused_mul_add, @@ -393,6 +396,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("overflow_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("overflow_mul"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("add_sat"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("sub_sat"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("sqrt"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("fused_mul_add"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 4ee4fb769..bdc381bc4 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2236,6 +2236,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_overflow_add: case BuiltinProc_overflow_sub: case BuiltinProc_overflow_mul: + case BuiltinProc_add_sat: + case BuiltinProc_sub_sat: { Type *main_type = tv.type; Type *type = main_type; @@ -2254,12 +2256,16 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_overflow_add: name = "llvm.uadd.with.overflow"; break; case BuiltinProc_overflow_sub: name = "llvm.usub.with.overflow"; break; case BuiltinProc_overflow_mul: name = "llvm.umul.with.overflow"; break; + case BuiltinProc_add_sat: name = "llvm.uadd.sat"; break; + case BuiltinProc_sub_sat: name = "llvm.usub.sat"; break; } } else { switch (id) { case BuiltinProc_overflow_add: name = "llvm.sadd.with.overflow"; break; case BuiltinProc_overflow_sub: name = "llvm.ssub.with.overflow"; break; case BuiltinProc_overflow_mul: name = "llvm.smul.with.overflow"; break; + case BuiltinProc_add_sat: name = "llvm.sadd.sat"; break; + case BuiltinProc_sub_sat: name = "llvm.ssub.sat"; break; } } LLVMTypeRef types[1] = {lb_type(p->module, type)}; -- cgit v1.2.3 From 853487e86cd1bede0c5179ed1ba796aad2200f39 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 16 Jul 2024 22:07:49 +0200 Subject: fix `add_sat` and `sub_sat` intrinsics --- base/intrinsics/intrinsics.odin | 9 ++++++--- src/check_builtin.cpp | 43 ++++++++++++++++++++++++++++++++++++++++- src/llvm_backend_proc.cpp | 42 ++++++++++++++++++++++++++++++++++------ 3 files changed, 84 insertions(+), 10 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 8a16ca40e..047373cda 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -38,9 +38,12 @@ count_leading_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_sim reverse_bits :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- byte_swap :: proc(x: $T) -> T where type_is_integer(T) || type_is_float(T) --- -overflow_add :: proc(lhs, rhs: $T) -> (T, bool) --- -overflow_sub :: proc(lhs, rhs: $T) -> (T, bool) --- -overflow_mul :: proc(lhs, rhs: $T) -> (T, bool) --- +overflow_add :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) --- +overflow_sub :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) --- +overflow_mul :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) --- + +add_sat :: proc(lhs, rhs: $T) -> T where type_is_integer(T) --- +sub_sat :: proc(lhs, rhs: $T) -> T where type_is_integer(T) --- sqrt :: proc(x: $T) -> T where type_is_float(T) || (type_is_simd_vector(T) && type_is_float(type_elem_type(T))) --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 26de3a112..b6b1f9874 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4261,6 +4261,47 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_overflow_add: case BuiltinProc_overflow_sub: case BuiltinProc_overflow_mul: + { + Operand x = {}; + Operand y = {}; + check_expr(c, &x, ce->args[0]); + check_expr(c, &y, ce->args[1]); + if (x.mode == Addressing_Invalid) { + return false; + } + if (y.mode == Addressing_Invalid) { + return false; + } + convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false; + convert_to_typed(c, &x, y.type); + if (is_type_untyped(x.type)) { + gbString xts = type_to_string(x.type); + error(x.expr, "Expected a typed integer for '%.*s', got %s", LIT(builtin_name), xts); + gb_string_free(xts); + return false; + } + if (!is_type_integer(x.type)) { + gbString xts = type_to_string(x.type); + error(x.expr, "Expected an integer for '%.*s', got %s", LIT(builtin_name), xts); + gb_string_free(xts); + return false; + } + Type *ct = core_type(x.type); + if (is_type_different_to_arch_endianness(ct)) { + GB_ASSERT(ct->kind == Type_Basic); + if (ct->Basic.flags & (BasicFlag_EndianLittle|BasicFlag_EndianBig)) { + gbString xts = type_to_string(x.type); + error(x.expr, "Expected an integer which does not specify the explicit endianness for '%.*s', got %s", LIT(builtin_name), xts); + gb_string_free(xts); + return false; + } + } + + operand->mode = Addressing_Value; + operand->type = make_optional_ok_type(default_type(x.type)); + } + break; + case BuiltinProc_add_sat: case BuiltinProc_sub_sat: { @@ -4300,7 +4341,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } operand->mode = Addressing_Value; - operand->type = make_optional_ok_type(default_type(x.type)); + operand->type = default_type(x.type); } break; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index bdc381bc4..e26b2e50f 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2236,8 +2236,6 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_overflow_add: case BuiltinProc_overflow_sub: case BuiltinProc_overflow_mul: - case BuiltinProc_add_sat: - case BuiltinProc_sub_sat: { Type *main_type = tv.type; Type *type = main_type; @@ -2256,16 +2254,12 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_overflow_add: name = "llvm.uadd.with.overflow"; break; case BuiltinProc_overflow_sub: name = "llvm.usub.with.overflow"; break; case BuiltinProc_overflow_mul: name = "llvm.umul.with.overflow"; break; - case BuiltinProc_add_sat: name = "llvm.uadd.sat"; break; - case BuiltinProc_sub_sat: name = "llvm.usub.sat"; break; } } else { switch (id) { case BuiltinProc_overflow_add: name = "llvm.sadd.with.overflow"; break; case BuiltinProc_overflow_sub: name = "llvm.ssub.with.overflow"; break; case BuiltinProc_overflow_mul: name = "llvm.smul.with.overflow"; break; - case BuiltinProc_add_sat: name = "llvm.sadd.sat"; break; - case BuiltinProc_sub_sat: name = "llvm.ssub.sat"; break; } } LLVMTypeRef types[1] = {lb_type(p->module, type)}; @@ -2291,6 +2285,42 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu return res; } + case BuiltinProc_add_sat: + case BuiltinProc_sub_sat: + { + Type *main_type = tv.type; + Type *type = main_type; + if (is_type_tuple(main_type)) { + type = main_type->Tuple.variables[0]->type; + } + + lbValue x = lb_build_expr(p, ce->args[0]); + lbValue y = lb_build_expr(p, ce->args[1]); + x = lb_emit_conv(p, x, type); + y = lb_emit_conv(p, y, type); + + char const *name = nullptr; + if (is_type_unsigned(type)) { + switch (id) { + case BuiltinProc_add_sat: name = "llvm.uadd.sat"; break; + case BuiltinProc_sub_sat: name = "llvm.usub.sat"; break; + } + } else { + switch (id) { + case BuiltinProc_add_sat: name = "llvm.sadd.sat"; break; + case BuiltinProc_sub_sat: name = "llvm.ssub.sat"; break; + } + } + LLVMTypeRef types[1] = {lb_type(p->module, type)}; + + LLVMValueRef args[2] = { x.value, y.value }; + + lbValue res = {}; + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); + res.type = type; + return res; + } + case BuiltinProc_sqrt: { Type *type = tv.type; -- cgit v1.2.3 From fd06be2243db3fa193702f881947eaa5f2ebf24b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 12:33:02 +0100 Subject: Allow `swizzle` to take more arguments than the original array length --- src/check_builtin.cpp | 2 +- src/llvm_backend_expr.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b6b1f9874..b96337326 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2460,7 +2460,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As arg_count++; } - if (arg_count > max_count) { + if (false && arg_count > max_count) { error(call, "Too many 'swizzle' indices, %td > %td", arg_count, max_count); return false; } else if (arg_count < 2) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 1f0719e13..59d5cce23 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3814,7 +3814,7 @@ gb_internal lbAddr lb_build_array_swizzle_addr(lbProcedure *p, AstCallExpr *ce, Type *type = base_type(lb_addr_type(addr)); GB_ASSERT(type->kind == Type_Array); i64 count = type->Array.count; - if (count <= 4) { + if (count <= 4 && index_count <= 4) { u8 indices[4] = {}; u8 index_count = 0; for (i32 i = 1; i < ce->args.count; i++) { -- cgit v1.2.3 From 9a01a13914e9b1f577399fed7ed09132306946b1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 13:13:19 +0100 Subject: Add `simd_reduce_any` and `simd_reduce_all` --- base/intrinsics/intrinsics.odin | 18 +++++++++++------- core/simd/simd.odin | 3 +++ src/check_builtin.cpp | 23 +++++++++++++++++++++++ src/checker_builtin_procs.hpp | 7 +++++++ src/llvm_backend_proc.cpp | 17 +++++++++++++++++ 5 files changed, 61 insertions(+), 7 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 37a42b904..277eafdf1 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -268,13 +268,17 @@ simd_lanes_ge :: proc(a, b: #simd[N]T) -> #simd[N]Integer --- simd_extract :: proc(a: #simd[N]T, idx: uint) -> T --- simd_replace :: proc(a: #simd[N]T, idx: uint, elem: T) -> #simd[N]T --- -simd_reduce_add_ordered :: proc(a: #simd[N]T) -> T --- -simd_reduce_mul_ordered :: proc(a: #simd[N]T) -> T --- -simd_reduce_min :: proc(a: #simd[N]T) -> T --- -simd_reduce_max :: proc(a: #simd[N]T) -> T --- -simd_reduce_and :: proc(a: #simd[N]T) -> T --- -simd_reduce_or :: proc(a: #simd[N]T) -> T --- -simd_reduce_xor :: proc(a: #simd[N]T) -> T --- +simd_reduce_add_ordered :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_mul_ordered :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_min :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_max :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_and :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_or :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_xor :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- + +simd_reduce_any :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- +simd_reduce_all :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- + simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T --- simd_select :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T --- diff --git a/core/simd/simd.odin b/core/simd/simd.odin index c5a594df6..6166f703b 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -115,6 +115,9 @@ reduce_and :: intrinsics.simd_reduce_and reduce_or :: intrinsics.simd_reduce_or reduce_xor :: intrinsics.simd_reduce_xor +reduce_any :: intrinsics.simd_reduce_any +reduce_all :: intrinsics.simd_reduce_all + // swizzle :: proc(a: #simd[N]T, indices: ..int) -> #simd[len(indices)]T swizzle :: builtin.swizzle diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b96337326..73a90ed62 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -775,6 +775,29 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return true; } + case BuiltinProc_simd_reduce_any: + case BuiltinProc_simd_reduce_all: + { + Operand x = {}; + check_expr(c, &x, ce->args[0]); if (x.mode == Addressing_Invalid) return false; + + if (!is_type_simd_vector(x.type)) { + error(x.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); + return false; + } + Type *elem = base_array_type(x.type); + if (!is_type_boolean(elem)) { + gbString xs = type_to_string(x.type); + error(x.expr, "'%.*s' expected a #simd type with a boolean element, got '%s'", LIT(builtin_name), xs); + gb_string_free(xs); + return false; + } + + operand->mode = Addressing_Value; + operand->type = t_untyped_bool; + return true; + } + case BuiltinProc_simd_shuffle: { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 3a2e1ce22..b6eb326d2 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -174,6 +174,9 @@ BuiltinProc__simd_begin, BuiltinProc_simd_reduce_or, BuiltinProc_simd_reduce_xor, + BuiltinProc_simd_reduce_any, + BuiltinProc_simd_reduce_all, + BuiltinProc_simd_shuffle, BuiltinProc_simd_select, @@ -501,6 +504,10 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_reduce_or"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_reduce_xor"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_reduce_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_reduce_all"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("simd_shuffle"), 2, true, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_select"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 2f736ff6c..ee121d6f2 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1527,6 +1527,23 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn return res; } + case BuiltinProc_simd_reduce_any: + case BuiltinProc_simd_reduce_all: + { + char const *name = nullptr; + switch (builtin_id) { + case BuiltinProc_simd_reduce_any: name = "llvm.vector.reduce.and"; break; + case BuiltinProc_simd_reduce_all: name = "llvm.vector.reduce.or"; break; + } + + LLVMTypeRef types[1] = { lb_type(p->module, arg0.type) }; + LLVMValueRef args[1] = { arg0.value }; + + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); + return res; + } + + case BuiltinProc_simd_shuffle: { Type *vt = arg0.type; -- cgit v1.2.3 From 90fc52c2ee2ac3e5c01744f57d1e02a30e19b55a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 13:19:01 +0100 Subject: Rename `add_sat` -> `saturating_add` --- base/intrinsics/intrinsics.odin | 7 +++++-- core/simd/simd.odin | 4 ++-- src/check_builtin.cpp | 12 ++++++------ src/checker_builtin_procs.hpp | 16 ++++++++-------- src/llvm_backend_proc.cpp | 20 ++++++++++---------- 5 files changed, 31 insertions(+), 28 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 277eafdf1..fadbda3fb 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -42,8 +42,8 @@ overflow_add :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) #option overflow_sub :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) #optional_ok --- overflow_mul :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) #optional_ok --- -add_sat :: proc(lhs, rhs: $T) -> T where type_is_integer(T) --- -sub_sat :: proc(lhs, rhs: $T) -> T where type_is_integer(T) --- +saturating_add :: proc(lhs, rhs: $T) -> T where type_is_integer(T) --- +saturating_sub :: proc(lhs, rhs: $T) -> T where type_is_integer(T) --- sqrt :: proc(x: $T) -> T where type_is_float(T) || (type_is_simd_vector(T) && type_is_float(type_elem_type(T))) --- @@ -227,6 +227,9 @@ simd_sub :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_mul :: proc(a, b: #simd[N]T) -> #simd[N]T --- simd_div :: proc(a, b: #simd[N]T) -> #simd[N]T where type_is_float(T) --- +simd_saturating_add :: proc(a, b: #simd[N]T) -> #simd[N]T where type_is_integer(T) --- +simd_saturating_sub :: proc(a, b: #simd[N]T) -> #simd[N]T where type_is_integer(T) --- + // Keeps Odin's Behaviour // (x << y) if y <= mask else 0 simd_shl :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T --- diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 6166f703b..46f6a0112 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -74,8 +74,8 @@ shl_masked :: intrinsics.simd_shl_masked shr_masked :: intrinsics.simd_shr_masked // Saturation Arithmetic -add_sat :: intrinsics.simd_add_sat -sub_sat :: intrinsics.simd_sub_sat +saturating_add :: intrinsics.simd_saturating_add +saturating_sub :: intrinsics.simd_saturating_sub bit_and :: intrinsics.simd_bit_and bit_or :: intrinsics.simd_bit_or diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 73a90ed62..b4967a56a 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -470,8 +470,8 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan } // Integer only - case BuiltinProc_simd_add_sat: - case BuiltinProc_simd_sub_sat: + case BuiltinProc_simd_saturating_add: + case BuiltinProc_simd_saturating_sub: case BuiltinProc_simd_bit_and: case BuiltinProc_simd_bit_or: case BuiltinProc_simd_bit_xor: @@ -501,8 +501,8 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan Type *elem = base_array_type(x.type); switch (id) { - case BuiltinProc_simd_add_sat: - case BuiltinProc_simd_sub_sat: + case BuiltinProc_simd_saturating_add: + case BuiltinProc_simd_saturating_sub: if (!is_type_integer(elem)) { gbString xs = type_to_string(x.type); error(x.expr, "'%.*s' expected a #simd type with an integer element, got '%s'", LIT(builtin_name), xs); @@ -4325,8 +4325,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; - case BuiltinProc_add_sat: - case BuiltinProc_sub_sat: + case BuiltinProc_saturating_add: + case BuiltinProc_saturating_sub: { Operand x = {}; Operand y = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index b6eb326d2..7fd71c36a 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -70,8 +70,8 @@ enum BuiltinProcId { BuiltinProc_overflow_sub, BuiltinProc_overflow_mul, - BuiltinProc_add_sat, - BuiltinProc_sub_sat, + BuiltinProc_saturating_add, + BuiltinProc_saturating_sub, BuiltinProc_sqrt, BuiltinProc_fused_mul_add, @@ -141,8 +141,8 @@ BuiltinProc__simd_begin, BuiltinProc_simd_shl_masked, // C logic BuiltinProc_simd_shr_masked, // C logic - BuiltinProc_simd_add_sat, // saturation arithmetic - BuiltinProc_simd_sub_sat, // saturation arithmetic + BuiltinProc_simd_saturating_add, // saturation arithmetic + BuiltinProc_simd_saturating_sub, // saturation arithmetic BuiltinProc_simd_bit_and, BuiltinProc_simd_bit_or, @@ -399,8 +399,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("overflow_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("overflow_mul"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("add_sat"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("sub_sat"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("saturating_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("saturating_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("sqrt"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("fused_mul_add"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -470,8 +470,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_shl_masked"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_shr_masked"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("simd_add_sat"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("simd_sub_sat"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_saturating_add"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_saturating_sub"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_bit_and"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_bit_or"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ee121d6f2..64db2ad36 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1646,13 +1646,13 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn } - case BuiltinProc_simd_add_sat: - case BuiltinProc_simd_sub_sat: + case BuiltinProc_simd_saturating_add: + case BuiltinProc_simd_saturating_sub: { char const *name = nullptr; switch (builtin_id) { - case BuiltinProc_simd_add_sat: name = is_signed ? "llvm.sadd.sat" : "llvm.uadd.sat"; break; - case BuiltinProc_simd_sub_sat: name = is_signed ? "llvm.ssub.sat" : "llvm.usub.sat"; break; + case BuiltinProc_simd_saturating_add: name = is_signed ? "llvm.sadd.sat" : "llvm.uadd.sat"; break; + case BuiltinProc_simd_saturating_sub: name = is_signed ? "llvm.ssub.sat" : "llvm.usub.sat"; break; } LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)}; @@ -2302,8 +2302,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu return res; } - case BuiltinProc_add_sat: - case BuiltinProc_sub_sat: + case BuiltinProc_saturating_add: + case BuiltinProc_saturating_sub: { Type *main_type = tv.type; Type *type = main_type; @@ -2316,13 +2316,13 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu char const *name = nullptr; if (is_type_unsigned(type)) { switch (id) { - case BuiltinProc_add_sat: name = "llvm.uadd.sat"; break; - case BuiltinProc_sub_sat: name = "llvm.usub.sat"; break; + case BuiltinProc_saturating_add: name = "llvm.uadd.sat"; break; + case BuiltinProc_saturating_sub: name = "llvm.usub.sat"; break; } } else { switch (id) { - case BuiltinProc_add_sat: name = "llvm.sadd.sat"; break; - case BuiltinProc_sub_sat: name = "llvm.ssub.sat"; break; + case BuiltinProc_saturating_add: name = "llvm.sadd.sat"; break; + case BuiltinProc_saturating_sub: name = "llvm.ssub.sat"; break; } } LLVMTypeRef types[1] = {lb_type(p->module, type)}; -- cgit v1.2.3 From 7e701d1677fbe594e0970824062d8b3564d33d26 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 13:46:24 +0100 Subject: Add `intrinsics.simd_gather` and ``intrinsics.simd_scatter` --- base/intrinsics/intrinsics.odin | 4 +++ core/simd/simd.odin | 5 ++++ src/check_builtin.cpp | 54 +++++++++++++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 6 +++++ src/llvm_backend_proc.cpp | 46 +++++++++++++++++++++++++++++++++++ 5 files changed, 115 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index fadbda3fb..5566c8c6c 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -283,6 +283,10 @@ simd_reduce_any :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- simd_reduce_all :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- +simd_gather :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- +simd_scatter :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- + + simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T --- simd_select :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T --- diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 46f6a0112..2fc0bc2c0 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -102,6 +102,11 @@ lanes_le :: intrinsics.simd_lanes_le lanes_gt :: intrinsics.simd_lanes_gt lanes_ge :: intrinsics.simd_lanes_ge + +// Gather and Scatter intrinsics +gather :: intrinsics.simd_gather +scatter :: intrinsics.simd_scatter + // extract :: proc(a: #simd[N]T, idx: uint) -> T extract :: intrinsics.simd_extract // replace :: proc(a: #simd[N]T, idx: uint, elem: T) -> #simd[N]T diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b4967a56a..99a989b4f 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -663,6 +663,60 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return true; } + case BuiltinProc_simd_gather: + case BuiltinProc_simd_scatter: + { + // gather (ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T + // scatter(ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) + + Operand ptr = {}; + Operand values = {}; + Operand mask = {}; + check_expr(c, &ptr, ce->args[0]); if (ptr.mode == Addressing_Invalid) return false; + check_expr(c, &values, ce->args[1]); if (values.mode == Addressing_Invalid) return false; + check_expr(c, &mask, ce->args[2]); if (mask.mode == Addressing_Invalid) return false; + if (!is_type_simd_vector(ptr.type)) { error(ptr.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } + if (!is_type_simd_vector(values.type)) { error(values.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } + if (!is_type_simd_vector(mask.type)) { error(mask.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } + + Type *ptr_elem = base_array_type(ptr.type); + if (!is_type_rawptr(ptr_elem)) { + gbString s = type_to_string(ptr.type); + error(ptr.expr, "Expected a simd vector of 'rawptr' for the addresses, got %s", s); + gb_string_free(s); + return false; + } + Type *mask_elem = base_array_type(mask.type); + + if (!is_type_integer(mask_elem) && !is_type_boolean(mask_elem)) { + gbString s = type_to_string(mask.type); + error(mask.expr, "Expected a simd vector of integers or booleans for the mask, got %s", s); + gb_string_free(s); + return false; + } + + i64 ptr_count = get_array_type_count(ptr.type); + i64 values_count = get_array_type_count(values.type); + i64 mask_count = get_array_type_count(mask.type); + if (ptr_count != values_count || + values_count != mask_count || + mask_count != ptr_count) { + gbString s = type_to_string(mask.type); + error(mask.expr, "All simd vectors must be of the same length, got %lld vs %lld vs %lld", cast(long long)ptr_count, cast(long long)values_count, cast(long long)mask_count); + gb_string_free(s); + return false; + } + + if (id == BuiltinProc_simd_gather) { + operand->mode = Addressing_Value; + operand->type = values.type; + } else { + operand->mode = Addressing_NoValue; + operand->type = nullptr; + } + return true; + } + case BuiltinProc_simd_extract: { Operand x = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 7fd71c36a..826c10e10 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -191,6 +191,9 @@ BuiltinProc__simd_begin, BuiltinProc_simd_lanes_rotate_left, BuiltinProc_simd_lanes_rotate_right, + BuiltinProc_simd_gather, + BuiltinProc_simd_scatter, + // Platform specific SIMD intrinsics BuiltinProc_simd_x86__MM_SHUFFLE, @@ -522,6 +525,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_lanes_rotate_left"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_lanes_rotate_right"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_gather"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_scatter"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_x86__MM_SHUFFLE"), 4, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 64db2ad36..5ccbd3399 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1688,6 +1688,52 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn return res; } + + case BuiltinProc_simd_gather: + case BuiltinProc_simd_scatter: + { + LLVMValueRef ptr = arg0.value; + LLVMValueRef val = arg1.value; + LLVMValueRef mask = arg2.value; + + unsigned count = cast(unsigned)get_array_type_count(arg0.type); + + LLVMTypeRef mask_type = LLVMVectorType(LLVMInt1TypeInContext(p->module->ctx), count); + mask = LLVMBuildTrunc(p->builder, mask, mask_type, ""); + + char const *name = nullptr; + switch (builtin_id) { + case BuiltinProc_simd_gather: name = "llvm.masked.gather"; break; + case BuiltinProc_simd_scatter: name = "llvm.masked.scatter"; break; + } + LLVMTypeRef types[2] = { + lb_type(p->module, arg1.type), + lb_type(p->module, arg0.type) + }; + + auto alignment = cast(unsigned long long)type_align_of(base_array_type(arg1.type)); + LLVMValueRef align = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), alignment, false); + + LLVMValueRef args[4] = {}; + switch (builtin_id) { + case BuiltinProc_simd_gather: + args[0] = ptr; + args[1] = align; + args[2] = mask; + args[3] = val; + break; + case BuiltinProc_simd_scatter: + args[0] = val; + args[1] = ptr; + args[2] = align; + args[3] = mask; + break; + } + + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); + return res; + + } } GB_PANIC("Unhandled simd intrinsic: '%.*s'", LIT(builtin_procs[builtin_id].name)); -- cgit v1.2.3 From 84ac56f77881c38762ad1a3cf66d4340c8d847d8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 14:08:41 +0100 Subject: Add `intrinsics.simd_masked_load` and `intrinsics.simd_masked_store` --- base/intrinsics/intrinsics.odin | 7 +++-- core/simd/simd.odin | 3 ++ src/check_builtin.cpp | 62 +++++++++++++++++++++++++++++------------ src/checker.cpp | 4 +-- src/checker_builtin_procs.hpp | 9 ++++-- src/llvm_backend_proc.cpp | 18 ++++++++++-- 6 files changed, 75 insertions(+), 28 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index 5566c8c6c..7aa56a9e9 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -283,8 +283,11 @@ simd_reduce_any :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- simd_reduce_all :: proc(a: #simd[N]T) -> T where type_is_boolean(T) --- -simd_gather :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- -simd_scatter :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- +simd_gather :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- +simd_scatter :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- + +simd_masked_load :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- +simd_masked_store :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T --- diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 2fc0bc2c0..f8924e5de 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -106,6 +106,9 @@ lanes_ge :: intrinsics.simd_lanes_ge // Gather and Scatter intrinsics gather :: intrinsics.simd_gather scatter :: intrinsics.simd_scatter +masked_load :: intrinsics.simd_gather +masked_store :: intrinsics.simd_scatter + // extract :: proc(a: #simd[N]T, idx: uint) -> T extract :: intrinsics.simd_extract diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 99a989b4f..b5851bc01 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -665,26 +665,40 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan case BuiltinProc_simd_gather: case BuiltinProc_simd_scatter: + case BuiltinProc_simd_masked_load: + case BuiltinProc_simd_masked_store: { // gather (ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T // scatter(ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) + // masked_load (ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T + // masked_store(ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) + Operand ptr = {}; Operand values = {}; Operand mask = {}; check_expr(c, &ptr, ce->args[0]); if (ptr.mode == Addressing_Invalid) return false; check_expr(c, &values, ce->args[1]); if (values.mode == Addressing_Invalid) return false; check_expr(c, &mask, ce->args[2]); if (mask.mode == Addressing_Invalid) return false; - if (!is_type_simd_vector(ptr.type)) { error(ptr.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } if (!is_type_simd_vector(values.type)) { error(values.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } if (!is_type_simd_vector(mask.type)) { error(mask.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } - Type *ptr_elem = base_array_type(ptr.type); - if (!is_type_rawptr(ptr_elem)) { - gbString s = type_to_string(ptr.type); - error(ptr.expr, "Expected a simd vector of 'rawptr' for the addresses, got %s", s); - gb_string_free(s); - return false; + if (id == BuiltinProc_simd_gather || id == BuiltinProc_simd_scatter) { + if (!is_type_simd_vector(ptr.type)) { error(ptr.expr, "'%.*s' expected a simd vector type", LIT(builtin_name)); return false; } + Type *ptr_elem = base_array_type(ptr.type); + if (!is_type_rawptr(ptr_elem)) { + gbString s = type_to_string(ptr.type); + error(ptr.expr, "Expected a simd vector of 'rawptr' for the addresses, got %s", s); + gb_string_free(s); + return false; + } + } else { + if (!is_type_pointer(ptr.type)) { + gbString s = type_to_string(ptr.type); + error(ptr.expr, "Expected a pointer type for the address, got %s", s); + gb_string_free(s); + return false; + } } Type *mask_elem = base_array_type(mask.type); @@ -695,19 +709,31 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return false; } - i64 ptr_count = get_array_type_count(ptr.type); - i64 values_count = get_array_type_count(values.type); - i64 mask_count = get_array_type_count(mask.type); - if (ptr_count != values_count || - values_count != mask_count || - mask_count != ptr_count) { - gbString s = type_to_string(mask.type); - error(mask.expr, "All simd vectors must be of the same length, got %lld vs %lld vs %lld", cast(long long)ptr_count, cast(long long)values_count, cast(long long)mask_count); - gb_string_free(s); - return false; + if (id == BuiltinProc_simd_gather || id == BuiltinProc_simd_scatter) { + i64 ptr_count = get_array_type_count(ptr.type); + i64 values_count = get_array_type_count(values.type); + i64 mask_count = get_array_type_count(mask.type); + if (ptr_count != values_count || + values_count != mask_count || + mask_count != ptr_count) { + gbString s = type_to_string(mask.type); + error(mask.expr, "All simd vectors must be of the same length, got %lld vs %lld vs %lld", cast(long long)ptr_count, cast(long long)values_count, cast(long long)mask_count); + gb_string_free(s); + return false; + } + } else { + i64 values_count = get_array_type_count(values.type); + i64 mask_count = get_array_type_count(mask.type); + if (values_count != mask_count) { + gbString s = type_to_string(mask.type); + error(mask.expr, "All simd vectors must be of the same length, got %lld vs %lld", cast(long long)values_count, cast(long long)mask_count); + gb_string_free(s); + return false; + } } - if (id == BuiltinProc_simd_gather) { + if (id == BuiltinProc_simd_gather || + id == BuiltinProc_simd_masked_load) { operand->mode = Addressing_Value; operand->type = values.type; } else { diff --git a/src/checker.cpp b/src/checker.cpp index 3eae271a0..60000ec29 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1651,9 +1651,9 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo if (mode == Addressing_Constant || mode == Addressing_Invalid) { expr->tav.value = value; - } else if (mode == Addressing_Value && is_type_typeid(type)) { + } else if (mode == Addressing_Value && type != nullptr && is_type_typeid(type)) { expr->tav.value = value; - } else if (mode == Addressing_Value && is_type_proc(type)) { + } else if (mode == Addressing_Value && type != nullptr && is_type_proc(type)) { expr->tav.value = value; } diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 826c10e10..a5f688cd8 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -193,7 +193,8 @@ BuiltinProc__simd_begin, BuiltinProc_simd_gather, BuiltinProc_simd_scatter, - + BuiltinProc_simd_masked_load, + BuiltinProc_simd_masked_store, // Platform specific SIMD intrinsics BuiltinProc_simd_x86__MM_SHUFFLE, @@ -525,8 +526,10 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_lanes_rotate_left"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_lanes_rotate_right"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("simd_gather"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("simd_scatter"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_gather"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_scatter"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_masked_load"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_masked_store"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_x86__MM_SHUFFLE"), 4, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 5ccbd3399..bfdac7c96 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1691,20 +1691,24 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn case BuiltinProc_simd_gather: case BuiltinProc_simd_scatter: + case BuiltinProc_simd_masked_load: + case BuiltinProc_simd_masked_store: { LLVMValueRef ptr = arg0.value; LLVMValueRef val = arg1.value; LLVMValueRef mask = arg2.value; - unsigned count = cast(unsigned)get_array_type_count(arg0.type); + unsigned count = cast(unsigned)get_array_type_count(arg1.type); LLVMTypeRef mask_type = LLVMVectorType(LLVMInt1TypeInContext(p->module->ctx), count); mask = LLVMBuildTrunc(p->builder, mask, mask_type, ""); char const *name = nullptr; switch (builtin_id) { - case BuiltinProc_simd_gather: name = "llvm.masked.gather"; break; - case BuiltinProc_simd_scatter: name = "llvm.masked.scatter"; break; + case BuiltinProc_simd_gather: name = "llvm.masked.gather"; break; + case BuiltinProc_simd_scatter: name = "llvm.masked.scatter"; break; + case BuiltinProc_simd_masked_load: name = "llvm.masked.load"; break; + case BuiltinProc_simd_masked_store: name = "llvm.masked.store"; break; } LLVMTypeRef types[2] = { lb_type(p->module, arg1.type), @@ -1716,12 +1720,20 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn LLVMValueRef args[4] = {}; switch (builtin_id) { + case BuiltinProc_simd_masked_load: + types[1] = lb_type(p->module, t_rawptr); + /*fallthrough*/ case BuiltinProc_simd_gather: args[0] = ptr; args[1] = align; args[2] = mask; args[3] = val; + // res.type = arg1.type; break; + + case BuiltinProc_simd_masked_store: + types[1] = lb_type(p->module, t_rawptr); + /*fallthrough*/ case BuiltinProc_simd_scatter: args[0] = val; args[1] = ptr; -- cgit v1.2.3 From f56abf37804240c508f0ca7f249176208d333c72 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Aug 2024 14:54:09 +0100 Subject: Add `intrinsics.masked_expand_load` and `intrinsics.masked_compress_store` --- base/intrinsics/intrinsics.odin | 4 ++++ core/simd/simd.odin | 3 ++- src/check_builtin.cpp | 7 ++++++- src/checker_builtin_procs.hpp | 4 ++++ src/llvm_backend_proc.cpp | 34 ++++++++++++++++++++++++++++------ 5 files changed, 44 insertions(+), 8 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index e78a41719..c78559f3f 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -286,6 +286,10 @@ simd_scatter :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) simd_masked_load :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- simd_masked_store :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- +simd_masked_expand_load :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- +simd_masked_compress_store :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- + + simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T --- simd_select :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T --- diff --git a/core/simd/simd.odin b/core/simd/simd.odin index e93c94687..1f3c67b72 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -108,7 +108,8 @@ gather :: intrinsics.simd_gather scatter :: intrinsics.simd_scatter masked_load :: intrinsics.simd_masked_load masked_store :: intrinsics.simd_masked_store - +masked_expand_load :: intrinsics.simd_masked_expand_load +masked_compress_store :: intrinsics.simd_masked_compress_store // extract :: proc(a: #simd[N]T, idx: uint) -> T extract :: intrinsics.simd_extract diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b5851bc01..bde102a8d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -667,12 +667,16 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan case BuiltinProc_simd_scatter: case BuiltinProc_simd_masked_load: case BuiltinProc_simd_masked_store: + case BuiltinProc_simd_masked_expand_load: + case BuiltinProc_simd_masked_compress_store: { // gather (ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T // scatter(ptr: #simd[N]rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) // masked_load (ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T // masked_store(ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) + // masked_expand_load (ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) -> #simd[N]T + // masked_compress_store(ptr: rawptr, values: #simd[N]T, mask: #simd[N]int_or_bool) Operand ptr = {}; Operand values = {}; @@ -733,7 +737,8 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan } if (id == BuiltinProc_simd_gather || - id == BuiltinProc_simd_masked_load) { + id == BuiltinProc_simd_masked_load || + id == BuiltinProc_simd_masked_expand_load) { operand->mode = Addressing_Value; operand->type = values.type; } else { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index a5f688cd8..6245dadaf 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -195,6 +195,8 @@ BuiltinProc__simd_begin, BuiltinProc_simd_scatter, BuiltinProc_simd_masked_load, BuiltinProc_simd_masked_store, + BuiltinProc_simd_masked_expand_load, + BuiltinProc_simd_masked_compress_store, // Platform specific SIMD intrinsics BuiltinProc_simd_x86__MM_SHUFFLE, @@ -530,6 +532,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_scatter"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_masked_load"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_masked_store"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_masked_expand_load"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_masked_compress_store"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_x86__MM_SHUFFLE"), 4, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ce1cc8586..ceaeb1aca 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1693,6 +1693,8 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn case BuiltinProc_simd_scatter: case BuiltinProc_simd_masked_load: case BuiltinProc_simd_masked_store: + case BuiltinProc_simd_masked_expand_load: + case BuiltinProc_simd_masked_compress_store: { LLVMValueRef ptr = arg0.value; LLVMValueRef val = arg1.value; @@ -1705,11 +1707,14 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn char const *name = nullptr; switch (builtin_id) { - case BuiltinProc_simd_gather: name = "llvm.masked.gather"; break; - case BuiltinProc_simd_scatter: name = "llvm.masked.scatter"; break; - case BuiltinProc_simd_masked_load: name = "llvm.masked.load"; break; - case BuiltinProc_simd_masked_store: name = "llvm.masked.store"; break; - } + case BuiltinProc_simd_gather: name = "llvm.masked.gather"; break; + case BuiltinProc_simd_scatter: name = "llvm.masked.scatter"; break; + case BuiltinProc_simd_masked_load: name = "llvm.masked.load"; break; + case BuiltinProc_simd_masked_store: name = "llvm.masked.store"; break; + case BuiltinProc_simd_masked_expand_load: name = "llvm.masked.expandload"; break; + case BuiltinProc_simd_masked_compress_store: name = "llvm.masked.compressstore"; break; + } + unsigned type_count = 2; LLVMTypeRef types[2] = { lb_type(p->module, arg1.type), lb_type(p->module, arg0.type) @@ -1718,6 +1723,7 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn auto alignment = cast(unsigned long long)type_align_of(base_array_type(arg1.type)); LLVMValueRef align = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), alignment, false); + unsigned arg_count = 4; LLVMValueRef args[4] = {}; switch (builtin_id) { case BuiltinProc_simd_masked_load: @@ -1739,9 +1745,25 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn args[2] = align; args[3] = mask; break; + + case BuiltinProc_simd_masked_expand_load: + arg_count = 3; + type_count = 1; + args[0] = ptr; + args[1] = mask; + args[2] = val; + break; + + case BuiltinProc_simd_masked_compress_store: + arg_count = 3; + type_count = 1; + args[0] = val; + args[1] = ptr; + args[2] = mask; + break; } - res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); + res.value = lb_call_intrinsic(p, name, args, arg_count, types, type_count); return res; } -- cgit v1.2.3 From efe68c2e24e0a38e591f146822ed93904e4193d7 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 27 Jul 2024 04:20:03 +0200 Subject: posix: add package --- core/c/libc/complex.odin | 4 +- core/c/libc/errno.odin | 2 +- core/c/libc/setjmp.odin | 19 +- core/c/libc/stdio.odin | 43 +- core/c/libc/stdlib.odin | 21 +- core/c/libc/string.odin | 2 +- core/c/libc/time.odin | 32 +- core/mem/virtual/virtual_darwin.odin | 153 +-- core/os/dir_unix.odin | 1 + core/os/os_darwin.odin | 72 +- core/os/os_freebsd.odin | 10 +- core/os/os_linux.odin | 6 +- core/os/os_netbsd.odin | 8 +- core/os/os_openbsd.odin | 6 +- core/path/filepath/path_unix.odin | 7 +- core/prof/spall/spall_unix.odin | 33 +- core/sys/posix/README.md | 57 + core/sys/posix/arpa_inet.odin | 58 + core/sys/posix/dirent.odin | 205 +++ core/sys/posix/dlfcn.odin | 115 ++ core/sys/posix/errno.odin | 373 ++++++ core/sys/posix/fcntl.odin | 415 +++++++ core/sys/posix/fnmatch.odin | 58 + core/sys/posix/glob.odin | 179 +++ core/sys/posix/grp.odin | 130 ++ core/sys/posix/iconv.odin | 50 + core/sys/posix/langinfo.odin | 285 +++++ core/sys/posix/libgen.odin | 74 ++ core/sys/posix/limits.odin | 459 +++++++ core/sys/posix/locale.odin | 93 ++ core/sys/posix/monetary.odin | 42 + core/sys/posix/net_if.odin | 60 + core/sys/posix/netdb.odin | 443 +++++++ core/sys/posix/netinet_in.odin | 199 +++ core/sys/posix/netinet_tcp.odin | 11 + core/sys/posix/poll.odin | 78 ++ core/sys/posix/posix.odin | 26 + core/sys/posix/pthread.odin | 518 ++++++++ core/sys/posix/pwd.odin | 168 +++ core/sys/posix/sched.odin | 105 ++ core/sys/posix/setjmp.odin | 58 + core/sys/posix/signal.odin | 1131 +++++++++++++++++ core/sys/posix/stdio.odin | 332 +++++ core/sys/posix/stdlib.odin | 450 +++++++ core/sys/posix/string.odin | 47 + core/sys/posix/sys_ipc.odin | 89 ++ core/sys/posix/sys_mman.odin | 229 ++++ core/sys/posix/sys_msg.odin | 161 +++ core/sys/posix/sys_resource.odin | 152 +++ core/sys/posix/sys_select.odin | 120 ++ core/sys/posix/sys_sem.odin | 132 ++ core/sys/posix/sys_shm.odin | 146 +++ core/sys/posix/sys_socket.odin | 491 ++++++++ core/sys/posix/sys_stat.odin | 540 ++++++++ core/sys/posix/sys_statvfs.odin | 135 ++ core/sys/posix/sys_time.odin | 82 ++ core/sys/posix/sys_times.odin | 38 + core/sys/posix/sys_uio.odin | 42 + core/sys/posix/sys_un.odin | 17 + core/sys/posix/sys_utsname.odin | 55 + core/sys/posix/sys_wait.odin | 380 ++++++ core/sys/posix/termios.odin | 475 +++++++ core/sys/posix/time.odin | 234 ++++ core/sys/posix/ulimit.odin | 43 + core/sys/posix/unistd.odin | 1914 +++++++++++++++++++++++++++++ core/sys/posix/utime.odin | 36 + core/sys/posix/wordexp.odin | 107 ++ core/sys/unix/pthread_netbsd.odin | 2 +- core/sys/unix/pthread_unix.odin | 5 + core/sys/unix/time_unix.odin | 83 -- core/time/time_linux.odin | 38 + core/time/time_unix.odin | 42 +- examples/all/all_posix.odin | 6 + src/big_int.cpp | 4 + src/check_builtin.cpp | 17 + src/check_decl.cpp | 20 +- src/checker_builtin_procs.hpp | 4 + tests/core/normal.odin | 1 + tests/core/sys/posix/posix.odin | 211 ++++ tests/core/sys/posix/structs.odin | 127 ++ tests/core/sys/posix/structs/.gitignore | 2 + tests/core/sys/posix/structs/structs.c | 103 ++ tests/core/sys/posix/structs/structs.odin | 74 ++ 83 files changed, 12666 insertions(+), 329 deletions(-) create mode 100644 core/sys/posix/README.md create mode 100644 core/sys/posix/arpa_inet.odin create mode 100644 core/sys/posix/dirent.odin create mode 100644 core/sys/posix/dlfcn.odin create mode 100644 core/sys/posix/errno.odin create mode 100644 core/sys/posix/fcntl.odin create mode 100644 core/sys/posix/fnmatch.odin create mode 100644 core/sys/posix/glob.odin create mode 100644 core/sys/posix/grp.odin create mode 100644 core/sys/posix/iconv.odin create mode 100644 core/sys/posix/langinfo.odin create mode 100644 core/sys/posix/libgen.odin create mode 100644 core/sys/posix/limits.odin create mode 100644 core/sys/posix/locale.odin create mode 100644 core/sys/posix/monetary.odin create mode 100644 core/sys/posix/net_if.odin create mode 100644 core/sys/posix/netdb.odin create mode 100644 core/sys/posix/netinet_in.odin create mode 100644 core/sys/posix/netinet_tcp.odin create mode 100644 core/sys/posix/poll.odin create mode 100644 core/sys/posix/posix.odin create mode 100644 core/sys/posix/pthread.odin create mode 100644 core/sys/posix/pwd.odin create mode 100644 core/sys/posix/sched.odin create mode 100644 core/sys/posix/setjmp.odin create mode 100644 core/sys/posix/signal.odin create mode 100644 core/sys/posix/stdio.odin create mode 100644 core/sys/posix/stdlib.odin create mode 100644 core/sys/posix/string.odin create mode 100644 core/sys/posix/sys_ipc.odin create mode 100644 core/sys/posix/sys_mman.odin create mode 100644 core/sys/posix/sys_msg.odin create mode 100644 core/sys/posix/sys_resource.odin create mode 100644 core/sys/posix/sys_select.odin create mode 100644 core/sys/posix/sys_sem.odin create mode 100644 core/sys/posix/sys_shm.odin create mode 100644 core/sys/posix/sys_socket.odin create mode 100644 core/sys/posix/sys_stat.odin create mode 100644 core/sys/posix/sys_statvfs.odin create mode 100644 core/sys/posix/sys_time.odin create mode 100644 core/sys/posix/sys_times.odin create mode 100644 core/sys/posix/sys_uio.odin create mode 100644 core/sys/posix/sys_un.odin create mode 100644 core/sys/posix/sys_utsname.odin create mode 100644 core/sys/posix/sys_wait.odin create mode 100644 core/sys/posix/termios.odin create mode 100644 core/sys/posix/time.odin create mode 100644 core/sys/posix/ulimit.odin create mode 100644 core/sys/posix/unistd.odin create mode 100644 core/sys/posix/utime.odin create mode 100644 core/sys/posix/wordexp.odin delete mode 100644 core/sys/unix/time_unix.odin create mode 100644 core/time/time_linux.odin create mode 100644 examples/all/all_posix.odin create mode 100644 tests/core/sys/posix/posix.odin create mode 100644 tests/core/sys/posix/structs.odin create mode 100644 tests/core/sys/posix/structs/.gitignore create mode 100644 tests/core/sys/posix/structs/structs.c create mode 100644 tests/core/sys/posix/structs/structs.odin (limited to 'src/check_builtin.cpp') diff --git a/core/c/libc/complex.odin b/core/c/libc/complex.odin index 81d2b75be..98fd7b1bb 100644 --- a/core/c/libc/complex.odin +++ b/core/c/libc/complex.odin @@ -47,8 +47,8 @@ foreign libc { clogf :: proc(z: complex_float) -> complex_float --- // 7.3.8 Power and absolute-value functions - cabs :: proc(z: complex_double) -> complex_double --- - cabsf :: proc(z: complex_float) -> complex_float --- + cabs :: proc(z: complex_double) -> double --- + cabsf :: proc(z: complex_float) -> float --- cpow :: proc(x, y: complex_double) -> complex_double --- cpowf :: proc(x, y: complex_float) -> complex_float --- csqrt :: proc(z: complex_double) -> complex_double --- diff --git a/core/c/libc/errno.odin b/core/c/libc/errno.odin index d28a24f56..843b2f1b6 100644 --- a/core/c/libc/errno.odin +++ b/core/c/libc/errno.odin @@ -102,6 +102,6 @@ when ODIN_OS == .Haiku { // read the value, or to produce an lvalue such that you can assign a different // error value to errno. To work around this, just expose it as a function like // it actually is. -errno :: #force_inline proc() -> ^int { +errno :: #force_inline proc "contextless" () -> ^int { return _get_errno() } diff --git a/core/c/libc/setjmp.odin b/core/c/libc/setjmp.odin index 68f5ac010..101b614b3 100644 --- a/core/c/libc/setjmp.odin +++ b/core/c/libc/setjmp.odin @@ -32,24 +32,21 @@ when ODIN_OS == .Windows { // the RDX register will contain zero and correctly set the flag to disable // stack unwinding. @(link_name="_setjmp") - setjmp :: proc(env: ^jmp_buf, hack: rawptr = nil) -> int --- + setjmp :: proc(env: ^jmp_buf, hack: rawptr = nil) -> int --- } } else { @(default_calling_convention="c") foreign libc { // 7.13.1 Save calling environment - // - // NOTE(dweiler): C11 requires setjmp be a macro, which means it won't - // necessarily export a symbol named setjmp but rather _setjmp in the case - // of musl, glibc, BSD libc, and msvcrt. - @(link_name="_setjmp") - setjmp :: proc(env: ^jmp_buf) -> int --- + @(link_name=LSETJMP) + setjmp :: proc(env: ^jmp_buf) -> int --- } } @(default_calling_convention="c") foreign libc { // 7.13.2 Restore calling environment + @(link_name=LLONGJMP) longjmp :: proc(env: ^jmp_buf, val: int) -> ! --- } @@ -64,3 +61,11 @@ foreign libc { // The choice of 4096 bytes for storage of this type is more than enough on all // relevant platforms. jmp_buf :: struct #align(16) { _: [4096]char, } + +when ODIN_OS == .NetBSD { + @(private) LSETJMP :: "__setjmp14" + @(private) LLONGJMP :: "__longjmp14" +} else { + @(private) LSETJMP :: "setjmp" + @(private) LLONGJMP :: "longjmp" +} diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin index 3e1d0f5a2..4be00ff0b 100644 --- a/core/c/libc/stdio.odin +++ b/core/c/libc/stdio.odin @@ -17,6 +17,12 @@ when ODIN_OS == .Windows { FILE :: struct {} +Whence :: enum int { + SET = SEEK_SET, + CUR = SEEK_CUR, + END = SEEK_END, +} + // MSVCRT compatible. when ODIN_OS == .Windows { _IOFBF :: 0x0000 @@ -101,6 +107,8 @@ when ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD { SEEK_CUR :: 1 SEEK_END :: 2 + TMP_MAX :: 308915776 + foreign libc { __sF: [3]FILE } @@ -128,6 +136,8 @@ when ODIN_OS == .FreeBSD { SEEK_CUR :: 1 SEEK_END :: 2 + TMP_MAX :: 308915776 + foreign libc { @(link_name="__stderrp") stderr: ^FILE @(link_name="__stdinp") stdin: ^FILE @@ -195,10 +205,21 @@ when ODIN_OS == .Haiku { } } +when ODIN_OS == .NetBSD { + @(private) LRENAME :: "__posix_rename" + @(private) LFGETPOS :: "__fgetpos50" + @(private) LFSETPOS :: "__fsetpos50" +} else { + @(private) LRENAME :: "rename" + @(private) LFGETPOS :: "fgetpos" + @(private) LFSETPOS :: "fsetpos" +} + @(default_calling_convention="c") foreign libc { // 7.21.4 Operations on files remove :: proc(filename: cstring) -> int --- + @(link_name=LRENAME) rename :: proc(old, new: cstring) -> int --- tmpfile :: proc() -> ^FILE --- tmpnam :: proc(s: [^]char) -> [^]char --- @@ -240,8 +261,10 @@ foreign libc { fwrite :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t --- // 7.21.9 File positioning functions + @(link_name=LFGETPOS) fgetpos :: proc(stream: ^FILE, pos: ^fpos_t) -> int --- - fseek :: proc(stream: ^FILE, offset: long, whence: int) -> int --- + fseek :: proc(stream: ^FILE, offset: long, whence: Whence) -> int --- + @(link_name=LFSETPOS) fsetpos :: proc(stream: ^FILE, pos: ^fpos_t) -> int --- ftell :: proc(stream: ^FILE) -> long --- rewind :: proc(stream: ^FILE) --- @@ -288,11 +311,11 @@ to_stream :: proc(file: ^FILE) -> io.Stream { return 0, unknown_or_eof(file) } - if fseek(file, long(offset), SEEK_SET) != 0 { + if fseek(file, long(offset), .SET) != 0 { return 0, unknown_or_eof(file) } - defer fseek(file, long(curr), SEEK_SET) + defer fseek(file, long(curr), .SET) n = i64(fread(raw_data(p), size_of(byte), len(p), file)) if n == 0 { err = unknown_or_eof(file) } @@ -307,17 +330,21 @@ to_stream :: proc(file: ^FILE) -> io.Stream { return 0, unknown_or_eof(file) } - if fseek(file, long(offset), SEEK_SET) != 0 { + if fseek(file, long(offset), .SET) != 0 { return 0, unknown_or_eof(file) } - defer fseek(file, long(curr), SEEK_SET) + defer fseek(file, long(curr), .SET) n = i64(fwrite(raw_data(p), size_of(byte), len(p), file)) if n == 0 { err = unknown_or_eof(file) } case .Seek: - if fseek(file, long(offset), int(whence)) != 0 { + #assert(int(Whence.SET) == int(io.Seek_From.Start)) + #assert(int(Whence.CUR) == int(io.Seek_From.Current)) + #assert(int(Whence.END) == int(io.Seek_From.End)) + + if fseek(file, long(offset), Whence(whence)) != 0 { return 0, unknown_or_eof(file) } @@ -326,9 +353,9 @@ to_stream :: proc(file: ^FILE) -> io.Stream { if curr == -1 { return 0, unknown_or_eof(file) } - defer fseek(file, curr, SEEK_SET) + defer fseek(file, curr, .SET) - if fseek(file, 0, SEEK_END) != 0 { + if fseek(file, 0, .END) != 0 { return 0, unknown_or_eof(file) } diff --git a/core/c/libc/stdlib.odin b/core/c/libc/stdlib.odin index d797b8746..08c6fa6f0 100644 --- a/core/c/libc/stdlib.odin +++ b/core/c/libc/stdlib.odin @@ -40,10 +40,9 @@ when ODIN_OS == .Linux { } -when ODIN_OS == .Darwin { +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD { RAND_MAX :: 0x7fffffff - // GLIBC and MUSL only @(private="file") @(default_calling_convention="c") foreign libc { @@ -55,6 +54,20 @@ when ODIN_OS == .Darwin { } } +when ODIN_OS == .NetBSD { + RAND_MAX :: 0x7fffffff + + @(private="file") + @(default_calling_convention="c") + foreign libc { + __mb_cur_max: size_t + } + + MB_CUR_MAX :: #force_inline proc() -> size_t { + return __mb_cur_max + } +} + // C does not declare what these values should be, as an implementation is free // to use any two distinct values it wants to indicate success or failure. // However, nobody actually does and everyone appears to have agreed upon these @@ -99,7 +112,7 @@ foreign libc { at_quick_exit :: proc(func: proc "c" ()) -> int --- exit :: proc(status: int) -> ! --- _Exit :: proc(status: int) -> ! --- - getenv :: proc(name: cstring) -> [^]char --- + getenv :: proc(name: cstring) -> cstring --- quick_exit :: proc(status: int) -> ! --- system :: proc(cmd: cstring) -> int --- @@ -150,4 +163,4 @@ aligned_free :: #force_inline proc "c" (ptr: rawptr) { } else { free(ptr) } -} \ No newline at end of file +} diff --git a/core/c/libc/string.odin b/core/c/libc/string.odin index e6a959f7b..cde9c7e6b 100644 --- a/core/c/libc/string.odin +++ b/core/c/libc/string.odin @@ -40,7 +40,7 @@ foreign libc { strtok :: proc(s1: [^]char, s2: cstring) -> [^]char --- // 7.24.6 Miscellaneous functions - strerror :: proc(errnum: int) -> [^]char --- + strerror :: proc(errnum: int) -> cstring --- strlen :: proc(s: cstring) -> size_t --- } memset :: proc "c" (s: rawptr, c: int, n: size_t) -> rawptr { diff --git a/core/c/libc/time.odin b/core/c/libc/time.odin index 924cf4aec..21859c602 100644 --- a/core/c/libc/time.odin +++ b/core/c/libc/time.odin @@ -50,30 +50,56 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS = foreign libc { // 7.27.2 Time manipulation functions clock :: proc() -> clock_t --- + @(link_name=LDIFFTIME) difftime :: proc(time1, time2: time_t) -> double --- + @(link_name=LMKTIME) mktime :: proc(timeptr: ^tm) -> time_t --- + @(link_name=LTIME) time :: proc(timer: ^time_t) -> time_t --- timespec_get :: proc(ts: ^timespec, base: int) -> int --- // 7.27.3 Time conversion functions asctime :: proc(timeptr: ^tm) -> [^]char --- + @(link_name=LCTIME) ctime :: proc(timer: ^time_t) -> [^]char --- + @(link_name=LGMTIME) gmtime :: proc(timer: ^time_t) -> ^tm --- + @(link_name=LLOCALTIME) localtime :: proc(timer: ^time_t) -> ^tm --- strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t --- } + when ODIN_OS == .NetBSD { + @(private) LDIFFTIME :: "__difftime50" + @(private) LMKTIME :: "__mktime50" + @(private) LTIME :: "__time50" + @(private) LCTIME :: "__ctime50" + @(private) LGMTIME :: "__gmtime50" + @(private) LLOCALTIME :: "__localtime50" + } else { + @(private) LDIFFTIME :: "difftime" + @(private) LMKTIME :: "mktime" + @(private) LTIME :: "ltime" + @(private) LCTIME :: "ctime" + @(private) LGMTIME :: "gmtime" + @(private) LLOCALTIME :: "localtime" + } + when ODIN_OS == .OpenBSD { CLOCKS_PER_SEC :: 100 } else { CLOCKS_PER_SEC :: 1000000 } - TIME_UTC :: 1 + TIME_UTC :: 1 - time_t :: distinct i64 + time_t :: distinct i64 - clock_t :: long + when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD { + clock_t :: distinct int32_t + } else { + clock_t :: distinct long + } timespec :: struct { tv_sec: time_t, diff --git a/core/mem/virtual/virtual_darwin.odin b/core/mem/virtual/virtual_darwin.odin index d2e3c8b51..9098866d0 100644 --- a/core/mem/virtual/virtual_darwin.odin +++ b/core/mem/virtual/virtual_darwin.odin @@ -2,141 +2,45 @@ //+private package mem_virtual -foreign import libc "system:System.framework" -import "core:c" - -PROT_NONE :: 0x0 /* [MC2] no permissions */ -PROT_READ :: 0x1 /* [MC2] pages can be read */ -PROT_WRITE :: 0x2 /* [MC2] pages can be written */ -PROT_EXEC :: 0x4 /* [MC2] pages can be executed */ - -// Sharing options -MAP_SHARED :: 0x1 /* [MF|SHM] share changes */ -MAP_PRIVATE :: 0x2 /* [MF|SHM] changes are private */ - -// Other flags -MAP_FIXED :: 0x0010 /* [MF|SHM] interpret addr exactly */ -MAP_RENAME :: 0x0020 /* Sun: rename private pages to file */ -MAP_NORESERVE :: 0x0040 /* Sun: don't reserve needed swap area */ -MAP_RESERVED0080 :: 0x0080 /* previously unimplemented MAP_INHERIT */ -MAP_NOEXTEND :: 0x0100 /* for MAP_FILE, don't change file size */ -MAP_HASSEMAPHORE :: 0x0200 /* region may contain semaphores */ -MAP_NOCACHE :: 0x0400 /* don't cache pages for this mapping */ -MAP_JIT :: 0x0800 /* Allocate a region that will be used for JIT purposes */ - -// Mapping type -MAP_FILE :: 0x0000 /* map from file (default) */ -MAP_ANONYMOUS :: 0x1000 /* allocated from memory, swap space */ - - -/* - * The MAP_RESILIENT_* flags can be used when the caller wants to map some - * possibly unreliable memory and be able to access it safely, possibly - * getting the wrong contents rather than raising any exception. - * For safety reasons, such mappings have to be read-only (PROT_READ access - * only). - * - * MAP_RESILIENT_CODESIGN: - * accessing this mapping will not generate code-signing violations, - * even if the contents are tainted. - * MAP_RESILIENT_MEDIA: - * accessing this mapping will not generate an exception if the contents - * are not available (unreachable removable or remote media, access beyond - * end-of-file, ...). Missing contents will be replaced with zeroes. - */ -MAP_RESILIENT_CODESIGN :: 0x2000 /* no code-signing failures */ -MAP_RESILIENT_MEDIA :: 0x4000 /* no backing-store failures */ - -MAP_32BIT :: 0x8000 /* Return virtual addresses <4G only */ - -// Flags used to support translated processes. -MAP_TRANSLATED_ALLOW_EXECUTE :: 0x20000 /* allow execute in translated processes */ -MAP_UNIX03 :: 0x40000 /* UNIX03 compliance */ - -// Process memory locking -MCL_CURRENT :: 0x0001 /* [ML] Lock only current memory */ -MCL_FUTURE :: 0x0002 /* [ML] Lock all future memory as well */ - -MADV_NORMAL :: 0 /* [MC1] no further special treatment */ -MADV_RANDOM :: 1 /* [MC1] expect random page refs */ -MADV_SEQUENTIAL :: 2 /* [MC1] expect sequential page refs */ -MADV_WILLNEED :: 3 /* [MC1] will need these pages */ -MADV_DONTNEED :: 4 /* [MC1] dont need these pages */ -MADV_FREE :: 5 /* pages unneeded, discard contents */ -MADV_ZERO_WIRED_PAGES :: 6 /* zero the wired pages that have not been unwired before the entry is deleted */ -MADV_FREE_REUSABLE :: 7 /* pages can be reused (by anyone) */ -MADV_FREE_REUSE :: 8 /* caller wants to reuse those pages */ -MADV_CAN_REUSE :: 9 -MADV_PAGEOUT :: 10 /* page out now (internal only) */ - -// msync() flags -MS_ASYNC :: 0x0001 /* [MF|SIO] return immediately */ -MS_INVALIDATE :: 0x0002 /* [MF|SIO] invalidate all cached data */ -MS_SYNC :: 0x0010 /* [MF|SIO] msync synchronously */ -MS_KILLPAGES :: 0x0004 /* invalidate pages, leave mapped */ -MS_DEACTIVATE :: 0x0008 /* deactivate pages, leave mapped */ - -// Return bits from mincore -MINCORE_INCORE :: 0x1 /* Page is incore */ -MINCORE_REFERENCED :: 0x2 /* Page has been referenced by us */ -MINCORE_MODIFIED :: 0x4 /* Page has been modified by us */ -MINCORE_REFERENCED_OTHER :: 0x8 /* Page has been referenced */ -MINCORE_MODIFIED_OTHER :: 0x10 /* Page has been modified */ -MINCORE_PAGED_OUT :: 0x20 /* Page has been paged out */ -MINCORE_COPIED :: 0x40 /* Page has been copied */ -MINCORE_ANONYMOUS :: 0x80 /* Page belongs to an anonymous object */ - -// Allocation failure result -MAP_FAILED : rawptr = rawptr(~uintptr(0)) - -foreign libc { - @(link_name="mlockall") _mlockall :: proc(flags: c.int) -> c.int --- - @(link_name="munlockall") _munlockall :: proc() -> c.int --- - @(link_name="mlock") _mlock :: proc(addr: rawptr, len: c.size_t) -> c.int --- - @(link_name="mmap") _mmap :: proc(addr: rawptr, len: c.size_t, prot: c.int, flags: c.int, fd: c.int, offset: int) -> rawptr --- - @(link_name="mprotect") _mprotect :: proc(addr: rawptr, len: c.size_t, prot: c.int) -> c.int --- - @(link_name="msync") _msync :: proc(addr: rawptr, len: c.size_t) -> c.int --- - @(link_name="munlock") _munlock :: proc(addr: rawptr, len: c.size_t) -> c.int --- - @(link_name="munmap") _munmap :: proc(addr: rawptr, len: c.size_t) -> c.int --- - @(link_name="shm_open") _shm_open :: proc(name: cstring, oflag: c.int, #c_vararg args: ..any) -> c.int --- - @(link_name="shm_unlink") _shm_unlink :: proc(name: cstring) -> c.int --- - @(link_name="posix_madvise") _posix_madvise :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int --- - @(link_name="madvise") _madvise :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int --- - @(link_name="mincore") _mincore :: proc(addr: rawptr, len: c.size_t, vec: cstring) -> c.int --- - @(link_name="minherit") _minherit :: proc(addr: rawptr, len: c.size_t, inherit: c.int) -> c.int --- -} +import "core:sys/posix" + +MAP_ANONYMOUS :: 0x1000 /* allocated from memory, swap space */ +MADV_FREE :: 5 /* pages unneeded, discard contents */ _reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { - result := _mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) - if result == MAP_FAILED { + flags := posix.Map_Flags{ .PRIVATE } + transmute(posix.Map_Flags)i32(MAP_ANONYMOUS) + result := posix.mmap(nil, size, {}, flags) + if result == posix.MAP_FAILED { return nil, .Out_Of_Memory } + return ([^]byte)(uintptr(result))[:size], nil } _commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error { - result := _mprotect(data, size, PROT_READ|PROT_WRITE) - if result != 0 { + if posix.mprotect(data, size, { .READ, .WRITE }) != .OK { return .Out_Of_Memory } + return nil } + _decommit :: proc "contextless" (data: rawptr, size: uint) { - _mprotect(data, size, PROT_NONE) - _madvise(data, size, MADV_FREE) + posix.mprotect(data, size, {}) + posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE)) } + _release :: proc "contextless" (data: rawptr, size: uint) { - _munmap(data, size) + posix.munmap(data, size) } + _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool { - pflags: c.int - pflags = PROT_NONE - if .Read in flags { pflags |= PROT_READ } - if .Write in flags { pflags |= PROT_WRITE } - if .Execute in flags { pflags |= PROT_EXEC } - err := _mprotect(data, size, pflags) - return err == 0 + #assert(i32(posix.Prot_Flag_Bits.READ) == i32(Protect_Flag.Read)) + #assert(i32(posix.Prot_Flag_Bits.WRITE) == i32(Protect_Flag.Write)) + #assert(i32(posix.Prot_Flag_Bits.EXEC) == i32(Protect_Flag.Execute)) + + return posix.mprotect(data, size, transmute(posix.Prot_Flags)flags) == .OK } @@ -149,16 +53,11 @@ _platform_memory_init :: proc() { _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { - prot, mflags: c.int - if .Read in flags { - prot |= PROT_READ - } - if .Write in flags { - prot |= PROT_WRITE - } - mflags |= MAP_SHARED - addr := _mmap(nil, c.size_t(size), prot, mflags, i32(fd), 0) - if addr == nil { + #assert(i32(posix.Prot_Flag_Bits.READ) == i32(Map_File_Flag.Read)) + #assert(i32(posix.Prot_Flag_Bits.WRITE) == i32(Map_File_Flag.Write)) + + addr := posix.mmap(nil, uint(size), transmute(posix.Prot_Flags)flags, { .SHARED }, posix.FD(fd)) + if addr == posix.MAP_FAILED || addr == nil { return nil, .Map_Failure } return ([^]byte)(addr)[:size], nil diff --git a/core/os/dir_unix.odin b/core/os/dir_unix.odin index b472e89b7..b0e8e0732 100644 --- a/core/os/dir_unix.odin +++ b/core/os/dir_unix.odin @@ -1,6 +1,7 @@ //+build darwin, linux, netbsd, freebsd, openbsd package os +import "base:runtime" import "core:strings" @(require_results) diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 0644ca645..940c0294e 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -584,7 +584,7 @@ F_GETPATH :: 50 // return the full path of the fd foreign libc { @(link_name="__error") __error :: proc() -> ^c.int --- - @(link_name="open") _unix_open :: proc(path: cstring, flags: i32, #c_vararg args: ..any) -> Handle --- + @(link_name="open") _unix_open :: proc(path: cstring, flags: i32, mode: u16) -> Handle --- @(link_name="close") _unix_close :: proc(handle: Handle) -> c.int --- @(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: c.size_t) -> int --- @(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: c.size_t) -> int --- @@ -628,23 +628,23 @@ foreign libc { @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring --- @(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int --- @(link_name="mkdir") _unix_mkdir :: proc(buf: cstring, mode: u16) -> c.int --- - @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- + @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring --- @(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring --- @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- - @(link_name="socket") _unix_socket :: proc(domain: int, type: int, protocol: int) -> int --- - @(link_name="listen") _unix_listen :: proc(socket: int, backlog: int) -> int --- - @(link_name="accept") _unix_accept :: proc(socket: int, addr: rawptr, addr_len: rawptr) -> int --- - @(link_name="connect") _unix_connect :: proc(socket: int, addr: rawptr, addr_len: socklen_t) -> int --- - @(link_name="bind") _unix_bind :: proc(socket: int, addr: rawptr, addr_len: socklen_t) -> int --- - @(link_name="setsockopt") _unix_setsockopt :: proc(socket: int, level: int, opt_name: int, opt_val: rawptr, opt_len: socklen_t) -> int --- - @(link_name="getsockopt") _unix_getsockopt :: proc(socket: int, level: int, opt_name: int, opt_val: rawptr, opt_len: socklen_t) -> int --- - @(link_name="recvfrom") _unix_recvfrom :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int, addr: rawptr, addr_len: ^socklen_t) -> c.ssize_t --- - @(link_name="recv") _unix_recv :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int) -> c.ssize_t --- - @(link_name="sendto") _unix_sendto :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int, addr: rawptr, addr_len: socklen_t) -> c.ssize_t --- - @(link_name="send") _unix_send :: proc(socket: int, buffer: rawptr, buffer_len: c.size_t, flags: int) -> c.ssize_t --- - @(link_name="shutdown") _unix_shutdown :: proc(socket: int, how: int) -> int --- + @(link_name="socket") _unix_socket :: proc(domain: c.int, type: c.int, protocol: c.int) -> c.int --- + @(link_name="listen") _unix_listen :: proc(socket: c.int, backlog: c.int) -> c.int --- + @(link_name="accept") _unix_accept :: proc(socket: c.int, addr: rawptr, addr_len: rawptr) -> c.int --- + @(link_name="connect") _unix_connect :: proc(socket: c.int, addr: rawptr, addr_len: socklen_t) -> c.int --- + @(link_name="bind") _unix_bind :: proc(socket: c.int, addr: rawptr, addr_len: socklen_t) -> c.int --- + @(link_name="setsockopt") _unix_setsockopt :: proc(socket: c.int, level: c.int, opt_name: c.int, opt_val: rawptr, opt_len: socklen_t) -> c.int --- + @(link_name="getsockopt") _unix_getsockopt :: proc(socket: c.int, level: c.int, opt_name: c.int, opt_val: rawptr, opt_len: ^socklen_t) -> c.int --- + @(link_name="recvfrom") _unix_recvfrom :: proc(socket: c.int, buffer: rawptr, buffer_len: c.size_t, flags: c.int, addr: rawptr, addr_len: ^socklen_t) -> c.ssize_t --- + @(link_name="recv") _unix_recv :: proc(socket: c.int, buffer: rawptr, buffer_len: c.size_t, flags: c.int) -> c.ssize_t --- + @(link_name="sendto") _unix_sendto :: proc(socket: c.int, buffer: rawptr, buffer_len: c.size_t, flags: c.int, addr: rawptr, addr_len: socklen_t) -> c.ssize_t --- + @(link_name="send") _unix_send :: proc(socket: c.int, buffer: rawptr, buffer_len: c.size_t, flags: c.int) -> c.ssize_t --- + @(link_name="shutdown") _unix_shutdown :: proc(socket: c.int, how: c.int) -> c.int --- @(link_name="getifaddrs") _getifaddrs :: proc(ifap: ^^ifaddrs) -> (c.int) --- @(link_name="freeifaddrs") _freeifaddrs :: proc(ifa: ^ifaddrs) --- @@ -661,9 +661,9 @@ when ODIN_ARCH != .arm64 { } foreign dl { - @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: int) -> rawptr --- + @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr --- @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr --- - @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> int --- + @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int --- @(link_name="dlerror") _unix_dlerror :: proc() -> cstring --- } @@ -1040,10 +1040,9 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { if path_ptr == nil { return "", get_last_error() } - defer _unix_free(path_ptr) + defer _unix_free(rawptr(path_ptr)) - path_cstr := cast(cstring)path_ptr - path = strings.clone(string(path_cstr)) + path = strings.clone(string(path_ptr)) return path, nil } @@ -1154,7 +1153,7 @@ current_thread_id :: proc "contextless" () -> int { dlopen :: proc(filename: string, flags: int) -> rawptr { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(filename, context.temp_allocator) - handle := _unix_dlopen(cstr, flags) + handle := _unix_dlopen(cstr, c.int(flags)) return handle } @(require_results) @@ -1208,26 +1207,24 @@ _alloc_command_line_arguments :: proc() -> []string { return res } -@(require_results) socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { - result := _unix_socket(domain, type, protocol) + result := _unix_socket(c.int(domain), c.int(type), c.int(protocol)) if result < 0 { return 0, get_last_error() } return Socket(result), nil } -@(require_results) connect :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> Error { - result := _unix_connect(int(sd), addr, len) + result := _unix_connect(c.int(sd), addr, len) if result < 0 { return get_last_error() } return nil } -bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> Error { - result := _unix_bind(int(sd), addr, len) +bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> (Error) { + result := _unix_bind(c.int(sd), addr, len) if result < 0 { return get_last_error() } @@ -1235,15 +1232,15 @@ bind :: proc(sd: Socket, addr: ^SOCKADDR, len: socklen_t) -> Error { } accept :: proc(sd: Socket, addr: ^SOCKADDR, len: rawptr) -> (Socket, Error) { - result := _unix_accept(int(sd), rawptr(addr), len) + result := _unix_accept(c.int(sd), rawptr(addr), len) if result < 0 { return 0, get_last_error() } return Socket(result), nil } -listen :: proc(sd: Socket, backlog: int) -> Error { - result := _unix_listen(int(sd), backlog) +listen :: proc(sd: Socket, backlog: int) -> (Error) { + result := _unix_listen(c.int(sd), c.int(backlog)) if result < 0 { return get_last_error() } @@ -1251,7 +1248,7 @@ listen :: proc(sd: Socket, backlog: int) -> Error { } setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Error { - result := _unix_setsockopt(int(sd), level, optname, optval, optlen) + result := _unix_setsockopt(c.int(sd), c.int(level), c.int(optname), optval, optlen) if result < 0 { return get_last_error() } @@ -1259,7 +1256,8 @@ setsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: } getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: socklen_t) -> Error { - result := _unix_getsockopt(int(sd), level, optname, optval, optlen) + optlen := optlen + result := _unix_getsockopt(c.int(sd), c.int(level), c.int(optname), optval, &optlen) if result < 0 { return get_last_error() } @@ -1267,7 +1265,7 @@ getsockopt :: proc(sd: Socket, level: int, optname: int, optval: rawptr, optlen: } recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_size: ^socklen_t) -> (u32, Error) { - result := _unix_recvfrom(int(sd), raw_data(data), len(data), flags, addr, addr_size) + result := _unix_recvfrom(c.int(sd), raw_data(data), len(data), c.int(flags), addr, addr_size) if result < 0 { return 0, get_last_error() } @@ -1275,7 +1273,7 @@ recvfrom :: proc(sd: Socket, data: []byte, flags: int, addr: ^SOCKADDR, addr_siz } recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { - result := _unix_recv(int(sd), raw_data(data), len(data), flags) + result := _unix_recv(c.int(sd), raw_data(data), len(data), c.int(flags)) if result < 0 { return 0, get_last_error() } @@ -1283,7 +1281,7 @@ recv :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { } sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: socklen_t) -> (u32, Error) { - result := _unix_sendto(int(sd), raw_data(data), len(data), flags, addr, addrlen) + result := _unix_sendto(c.int(sd), raw_data(data), len(data), c.int(flags), addr, addrlen) if result < 0 { return 0, get_last_error() } @@ -1291,15 +1289,15 @@ sendto :: proc(sd: Socket, data: []u8, flags: int, addr: ^SOCKADDR, addrlen: soc } send :: proc(sd: Socket, data: []byte, flags: int) -> (u32, Error) { - result := _unix_send(int(sd), raw_data(data), len(data), 0) + result := _unix_send(c.int(sd), raw_data(data), len(data), 0) if result < 0 { return 0, get_last_error() } return u32(result), nil } -shutdown :: proc(sd: Socket, how: int) -> Error { - result := _unix_shutdown(int(sd), how) +shutdown :: proc(sd: Socket, how: int) -> (Error) { + result := _unix_shutdown(c.int(sd), c.int(how)) if result < 0 { return get_last_error() } diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index e37f9767b..ba7e7ccf3 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -371,7 +371,7 @@ F_KINFO :: 22 foreign libc { @(link_name="__error") __Error_location :: proc() -> ^c.int --- - @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle --- + @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.uint16_t) -> Handle --- @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- @@ -402,7 +402,7 @@ foreign libc { @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr --- @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- - @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- + @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring --- @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- @@ -430,7 +430,7 @@ get_last_error :: proc "contextless" () -> Error { open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) - handle := _unix_open(cstr, c.int(flags), c.int(mode)) + handle := _unix_open(cstr, c.int(flags), u16(mode)) if handle == -1 { return INVALID_HANDLE, get_last_error() } @@ -786,10 +786,10 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { if path_ptr == nil { return "", get_last_error() } - defer _unix_free(path_ptr) + defer _unix_free(rawptr(path_ptr)) - path = strings.clone(string(cstring(path_ptr))) + path = strings.clone(string(path_ptr)) return path, nil } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 78da32a57..0fcd1a21a 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -491,7 +491,7 @@ foreign libc { @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- @(link_name="putenv") _unix_putenv :: proc(cstring) -> c.int --- @(link_name="setenv") _unix_setenv :: proc(key: cstring, value: cstring, overwrite: c.int) -> c.int --- - @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- + @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring --- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- } @@ -917,9 +917,9 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { if path_ptr == nil { return "", get_last_error() } - defer _unix_free(path_ptr) + defer _unix_free(rawptr(path_ptr)) - path = strings.clone(string(cstring(path_ptr))) + path = strings.clone(string(path_ptr)) return path, nil } diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index ffaf4a5f8..fac1bc311 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -330,7 +330,7 @@ dev_t :: u64 ino_t :: u64 nlink_t :: u32 off_t :: i64 -mode_t :: u16 +mode_t :: u32 pid_t :: u32 uid_t :: u32 gid_t :: u32 @@ -454,7 +454,7 @@ foreign libc { @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr --- @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- - @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- + @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring --- @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- @@ -832,9 +832,9 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { if path_ptr == nil { return "", get_last_error() } - defer _unix_free(path_ptr) + defer _unix_free(rawptr(path_ptr)) - path = strings.clone(string(cstring(path_ptr))) + path = strings.clone(string(path_ptr)) return path, nil } diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index a41637ea3..caae19e6e 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -379,7 +379,7 @@ foreign libc { @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr --- @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- - @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- + @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring --- @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! --- @@ -746,9 +746,9 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Error) { if path_ptr == nil { return "", get_last_error() } - defer _unix_free(path_ptr) + defer _unix_free(rawptr(path_ptr)) - path = strings.clone(string(cstring(path_ptr))) + path = strings.clone(string(path_ptr)) return path, nil } diff --git a/core/path/filepath/path_unix.odin b/core/path/filepath/path_unix.odin index b44a6a344..361bba49a 100644 --- a/core/path/filepath/path_unix.odin +++ b/core/path/filepath/path_unix.odin @@ -32,10 +32,9 @@ abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { if path_ptr == nil { return "", __error()^ == 0 } - defer _unix_free(path_ptr) + defer _unix_free(rawptr(path_ptr)) - path_cstr := cstring(path_ptr) - path_str := strings.clone(string(path_cstr), allocator) + path_str := strings.clone(string(path_ptr), allocator) return path_str, true } @@ -52,7 +51,7 @@ join :: proc(elems: []string, allocator := context.allocator) -> string { @(private) foreign libc { - realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- + realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring --- @(link_name="free") _unix_free :: proc(ptr: rawptr) --- } diff --git a/core/prof/spall/spall_unix.odin b/core/prof/spall/spall_unix.odin index 174b3a11b..fc05b8525 100644 --- a/core/prof/spall/spall_unix.odin +++ b/core/prof/spall/spall_unix.odin @@ -5,22 +5,7 @@ package spall // Only for types. import "core:os" -when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" -} else { - foreign import libc "system:c" -} - -timespec :: struct { - tv_sec: i64, // seconds - tv_nsec: i64, // nanoseconds -} - -foreign libc { - __error :: proc() -> ^i32 --- - @(link_name="write") _unix_write :: proc(handle: os.Handle, buffer: rawptr, count: uint) -> int --- - @(link_name="clock_gettime") _unix_clock_gettime :: proc(clock_id: u64, timespec: ^timespec) -> i32 --- -} +import "core:sys/posix" MAX_RW :: 0x7fffffff @@ -32,7 +17,7 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.E for n < len(data) { chunk := data[:min(len(data), MAX_RW)] - written := _unix_write(fd, raw_data(chunk), len(chunk)) + written := posix.write(posix.FD(fd), raw_data(chunk), len(chunk)) if written < 0 { return n, os.get_last_error() } @@ -42,11 +27,17 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.E return n, nil } -CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP. +// NOTE(tetra): "RAW" means: Not adjusted by NTP. +when ODIN_OS == .Darwin { + CLOCK :: posix.Clock(4) // CLOCK_MONOTONIC_RAW +} else { + // It looks like the BSDs don't have a CLOCK_MONOTONIC_RAW equivalent. + CLOCK :: posix.Clock.MONOTONIC +} @(no_instrumentation) _tick_now :: proc "contextless" () -> (ns: i64) { - t: timespec - _unix_clock_gettime(CLOCK_MONOTONIC_RAW, &t) - return t.tv_sec*1e9 + t.tv_nsec + t: posix.timespec + posix.clock_gettime(CLOCK, &t) + return i64(t.tv_sec)*1e9 + i64(t.tv_nsec) } diff --git a/core/sys/posix/README.md b/core/sys/posix/README.md new file mode 100644 index 000000000..4afe50d6a --- /dev/null +++ b/core/sys/posix/README.md @@ -0,0 +1,57 @@ +# POSIX + +defines bindings for most posix APIs. + +If a header is added, all of it must be implemented. + +Each platform must define the exact same symbols, different values are allowed, even structs with different non-standard fields. + +APIs part of extensions may be left out completely if one target doesn't implement it. + +APIs with a direct replacement in `core` might not be implemented. + +Macros are emulated with force inlined functions. + +Struct fields defined by the posix standard (and thus portable) are documented with `[PSX]`. + + +ADD A TEST FOR SIGINFO, one thread signalling and retrieving the signal out of siginfo or something. +ADD A TEST FOR wait.h +ADD A TEST FOR pthread. +ADDD A test for stat.h. +ADD A TEST FOR setjmp.h. +HAIKU. + +Unimplemented POSIX headers: + +- aio.h +- complex.h | See `core:c/libc` and our own complex types +- cpio.h +- ctype.h | See `core:c/libc` for most of it +- ndbm.h | Never seen or heard of it +- fenv.h +- float.h +- fmtmsg.h +- ftw.h +- semaphore.h | See `core:sync` +- inttypes.h | See `core:c` +- iso646.h | Impossible +- math.h | See `core:c/libc` +- mqueue.h | Targets don't seem to have implemented it +- regex.h | See `core:regex` +- search.h | Not useful in Odin +- spawn.h | Use `fork`, `execve`, etc. +- stdarg.h | See `core:c/libc` +- stdint.h | See `core:c` +- stropts.h +- syslog.h +- pthread.h | Only the actual threads API is bound, see `core:sync` for synchronization primitives +- string.h | Most of this is not useful in Odin, only a select few symbols are bound +- tar.h +- tgmath.h +- trace.h +- wchar.h +- wctype.h + +TODO: +- time.h | Docs diff --git a/core/sys/posix/arpa_inet.odin b/core/sys/posix/arpa_inet.odin new file mode 100644 index 000000000..7e950c4be --- /dev/null +++ b/core/sys/posix/arpa_inet.odin @@ -0,0 +1,58 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// arpa/inet.h - definitions for internet operations + +foreign lib { + // Use Odin's native big endian types `u32be` and `u16be` instead. + // htonl :: proc(c.uint32_t) -> c.uint32_t --- + // htons :: proc(c.uint16_t) -> c.uint16_t --- + // ntohl :: proc(c.uint32_t) -> c.uint32_t --- + // ntohs :: proc(c.uint16_t) -> c.uint16_t --- + + // Use of this function is problematic because -1 is a valid address (255.255.255.255). + // Avoid its use in favor of inet_aton(), inet_pton(3), or getaddrinfo(3) which provide a cleaner way to indicate error return. + // inet_addr :: proc(cstring) -> in_addr_t --- + + // Convert the Internet host address specified by in to a string in the Internet standard dot notation. + // + // NOTE: returns a static string overwritten by further calls. + // + // [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntoa.html ]] + inet_ntoa :: proc(in_addr) -> cstring --- + + // Convert a numeric address into a text string suitable for presentation. + // + // Returns `nil` and sets `errno` on failure. + // + // [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntop.html ]] + inet_ntop :: proc( + af: AF, // INET or INET6 + src: rawptr, // either ^in_addr or ^in_addr6 + dst: [^]byte, // use `INET_ADDRSTRLEN` or `INET6_ADDRSTRLEN` for minimum lengths + size: socklen_t, + ) -> cstring --- + + // Convert an address in its standard text presentation form into its numeric binary form. + // + // [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/inet_ntop.html ]] + inet_pton :: proc( + af: AF, // INET or INET6 + src: cstring, + dst: rawptr, // either ^in_addr or ^in_addr6 + size: socklen_t, // size_of(dst^) + ) -> pton_result --- +} + +pton_result :: enum c.int { + AFNOSUPPORT = -1, + INVALID = 0, + SUCCESS = 1, +} diff --git a/core/sys/posix/dirent.odin b/core/sys/posix/dirent.odin new file mode 100644 index 000000000..bbb5416c5 --- /dev/null +++ b/core/sys/posix/dirent.odin @@ -0,0 +1,205 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// dirent.h - format of directory entries + +foreign lib { + /* + can be used as the comparison function for the scandir() function to sort the directory entries, d1 and d2, into alphabetical order. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/scandir.html ]] + */ + @(link_name=LALPHASORT) + alphasort :: proc([^]^dirent, [^]^dirent) -> c.int --- + + /* + Scan the directory dir, calling the function referenced by sel on each directory entry. + + Example: + list: [^]^posix.dirent + ret := posix.scandir(#directory, &list, nil, posix.alphasort) + if ret < 0 { + panic(string(posix.strerror(posix.errno()))) + } + defer posix.free(list) + + entries := list[:ret] + for entry in entries { + log.info(entry) + posix.free(entry) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/scandir.html ]] + */ + @(link_name=LSCANDIR) + scandir :: proc( + dir: cstring, + sel: ^[^]^dirent, + filter: proc "c" (^dirent) -> b32 = nil, + compar: proc "c" ([^]^dirent, [^]^dirent) -> c.int = alphasort, + ) -> c.int --- + + /* + Close the directory stream referred to by the argument dirp. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/closedir.html ]] + */ + closedir :: proc(dirp: DIR) -> result --- + + /* + Return a file descriptor referring to the same directory as the dirp argument. + + // TODO: this is a macro on NetBSD? + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dirfd.html ]] + */ + dirfd :: proc(dirp: DIR) -> FD --- + + /* + Equivalent to the opendir() function except that the directory is specified by a file descriptor + rather than by a name. + The file offset associated with the file descriptor at the time of the call determines + which entries are returned. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopendir.html ]] + */ + @(link_name="fdopendir" + INODE_SUFFIX) + fdopendir :: proc(dirp: FD) -> DIR --- + + /* + Open a directory stream corresponding to the directory named by the dirname argument. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopendir.html ]] + */ + @(link_name=LOPENDIR) + opendir :: proc(path: cstring) -> DIR --- + + /* + Returns a pointer to a structure representing the directory entry at the current position + in the directory stream specified by the argument dirp, and position the directory stream at + the next entry. + + Returns nil when the end is reached or an error occurred (which sets errno). + + Example: + posix.set_errno(.NONE) + entry := posix.readdir(dirp) + if entry == nil { + if errno := posix.errno(); errno != .NONE { + panic(string(posix.strerror(errno))) + } else { + fmt.println("end of directory stream") + } + } else { + fmt.println(entry) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/readdir.html ]] + */ + @(link_name=LREADDIR) + readdir :: proc(dirp: DIR) -> ^dirent --- + + /* + Reset the position of the directory stream to which dirp refers to the beginning of the directory. + It shall also cause the directory stream to refer to the current state of the corresponding directory, + as a call to opendir() would have done. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/rewinddir.html ]] + */ + @(link_name="rewinddir" + INODE_SUFFIX) + rewinddir :: proc(dirp: DIR) --- + + /* + The seekdir() function shall set the position of the next readdir() operation on the directory + stream specified by dirp to the position specified by loc. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/seekdir.html ]] + */ + @(link_name="seekdir" + INODE_SUFFIX) + seekdir :: proc(dirp: DIR, loc: dir_loc) --- + + /* + The telldir() function shall obtain the current location associated with the directory stream + specified by dirp. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/telldir.html ]] + */ + @(link_name="telldir" + INODE_SUFFIX) + telldir :: proc(dirp: DIR) -> dir_loc --- + + // deprecated. + // readdir_r :: proc(DIR, ^dirent, ^^dirent) -> c.int --- +} + +DIR :: distinct rawptr + +dir_loc :: c.long + +// NOTE: `d_type` is not a POSIX standard field, but all targets we support add it. +D_Type :: enum c.uint8_t { + UNKNOWN = 0, + FIFO = 1, + CHR = 2, + DIR = 4, + BLK = 6, + REG = 8, + LNK = 10, + SOCK = 12, + WHT = 14, +} + +when ODIN_OS == .NetBSD { + @(private) LALPHASORT :: "__alphasort30" + @(private) LSCANDIR :: "__scandir30" + @(private) LOPENDIR :: "__opendir30" + @(private) LREADDIR :: "__readdir30" +} else { + @(private) LALPHASORT :: "alphasort" + INODE_SUFFIX + @(private) LSCANDIR :: "scandir" + INODE_SUFFIX + @(private) LOPENDIR :: "opendir" + INODE_SUFFIX + @(private) LREADDIR :: "readdir" + INODE_SUFFIX +} + +when ODIN_OS == .Darwin { + + dirent :: struct { + d_ino: ino_t, /* [PSX] file number of entry */ + d_seekoff: c.uint64_t, /* seek offset */ + d_reclen: c.uint16_t, /* length of this record */ + d_namelen: c.uint16_t, /* length of string in d_name */ + d_type: D_Type, /* file type */ + d_name: [1024]c.char `fmt:"s,0"`, /* [PSX] entry name */ + } + +} else when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD { + + dirent :: struct { + d_ino: ino_t, /* [PSX] file number of entry */ + d_off: off_t, /* directory offset of the next entry */ + d_reclen: c.uint16_t, /* length of this record */ + d_type: D_Type, /* file type */ + d_namelen: c.uint8_t, /* length of string in d_name */ + d_pad0: c.uint32_t, + d_name: [256]c.char `fmt:"s,0"`, /* [PSX] entry name */ + } + +} else when ODIN_OS == .NetBSD { + + dirent :: struct { + d_ino: ino_t, /* [PSX] file number of entry */ + d_reclen: c.uint16_t, /* length of this record */ + d_namelen: c.uint16_t, /* length of string in d_name */ + d_type: D_Type, /* file type */ + d_name: [512]c.char `fmt:"s,0"`, /* [PSX] entry name */ + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/dlfcn.odin b/core/sys/posix/dlfcn.odin new file mode 100644 index 000000000..0ee666e24 --- /dev/null +++ b/core/sys/posix/dlfcn.odin @@ -0,0 +1,115 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// dlfcn.h - dynamic linking + +foreign lib { + /* + inform the system that the object referenced by a handle returned from a previous dlopen() + invocation is no longer needed by the application. + + Returns: 0 on success, non-zero on failure (use dlerror() for more information) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlclose.html ]] + */ + dlclose :: proc(handle: Symbol_Table) -> c.int --- + + /* + return a null-terminated character string (with no trailing ) that describes + the last error that occurred during dynamic linking processing. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlerror.html ]] + */ + dlerror :: proc() -> cstring --- + + /* + Make the symbols (function identifiers and data object identifiers) in the executable object + file specified by file available to the calling program. + + Returns: a reference to the symbol table on success, nil on failure (use dlerror() for more information) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html ]] + */ + dlopen :: proc(file: cstring, mode: RTLD_Flags) -> Symbol_Table --- + + /* + Obtain the address of a symbol (a function identifier or a data object identifier) + defined in the symbol table identified by the handle argument. + + Returns: the address of the matched symbol on success, nil on failure (use dlerror() for more information) + + Example: + handle := posix.dlopen("/usr/home/me/libfoo.so", posix.RTLD_LOCAL + { .RTLD_LAZY }) + defer posix.dlclose(handle) + + if handle == nil { + panic(string(posix.dlerror())) + } + + foo: proc(a, b: int) -> int + foo = auto_cast posix.dlsym(handle, "foo") + + if foo == nil { + panic(string(posix.dlerror())) + } + + fmt.printfln("foo(%v, %v) == %v", 1, 2, foo(1, 2)) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html ]] + */ + dlsym :: proc(handle: Symbol_Table, name: cstring) -> rawptr --- +} + +RTLD_Flag_Bits :: enum c.int { + LAZY = log2(RTLD_LAZY), + NOW = log2(RTLD_NOW), + GLOBAL = log2(RTLD_GLOBAL), + + // NOTE: use with `posix.RTLD_LOCAL + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in + // this bit set enum because it is 0 on some platforms and a value on others. + // LOCAL = RTLD_LOCAL + + _MAX = 31, +} +RTLD_Flags :: bit_set[RTLD_Flag_Bits; c.int] + +Symbol_Table :: distinct rawptr + +when ODIN_OS == .Darwin { + + RTLD_LAZY :: 0x1 + RTLD_NOW :: 0x2 + _RTLD_LOCAL :: 0x4 + RTLD_GLOBAL :: 0x8 + + RTLD_LOCAL :: RTLD_Flags{RTLD_Flag_Bits(log2(_RTLD_LOCAL))} + +} else when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD { + + RTLD_LAZY :: 1 + RTLD_NOW :: 2 + _RTLD_LOCAL :: 0 + RTLD_GLOBAL :: 0x100 + + RTLD_LOCAL :: RTLD_Flags{} + +} else when ODIN_OS == .NetBSD { + + RTLD_LAZY :: 0x1 + RTLD_NOW :: 0x2 + _RTLD_LOCAL :: 0x200 + RTLD_GLOBAL :: 0x100 + + RTLD_LOCAL :: RTLD_Flags{RTLD_Flag_Bits(log2(_RTLD_LOCAL))} + +} else { + #panic("posix is unimplemented for the current target") +} + diff --git a/core/sys/posix/errno.odin b/core/sys/posix/errno.odin new file mode 100644 index 000000000..4ef10aadf --- /dev/null +++ b/core/sys/posix/errno.odin @@ -0,0 +1,373 @@ +package posix + +import "core:c" +import "core:c/libc" + +// errno.h - system error numbers + +EDOM :: libc.EDOM +EILSEQ :: libc.EILSEQ +ERANGE :: libc.ERANGE + +@(no_instrumentation) +get_errno :: #force_inline proc "contextless" () -> Errno { + return (^Errno)(libc.errno())^ +} + +set_errno :: #force_inline proc "contextless" (err: Errno) { + libc.errno()^ = i32(err) +} + +errno :: proc { + get_errno, + set_errno, +} + +Errno :: enum c.int { + NONE = 0, + EDOM = EDOM, + EILSEQ = EILSEQ, + ERANGE = ERANGE, + E2BIG = E2BIG, + EACCES = EACCES, + EADDRINUSE = EADDRINUSE, + EADDRNOTAVAIL = EADDRNOTAVAIL, + EAFNOSUPPORT = EAFNOSUPPORT, + EAGAIN = EAGAIN, + EALREADY = EALREADY, + EBADF = EBADF, + EBADMSG = EBADMSG, + EBUSY = EBUSY, + ECANCELED = ECANCELED, + ECHILD = ECHILD, + ECONNABORTED = ECONNABORTED, + ECONNREFUSED = ECONNREFUSED, + ECONNRESET = ECONNRESET, + EDEADLK = EDEADLK, + EDESTADDRREQ = EDESTADDRREQ, + EDQUOT = EDQUOT, + EEXIST = EEXIST, + EFAULT = EFAULT, + EFBIG = EFBIG, + EHOSTUNREACH = EHOSTUNREACH, + EIDRM = EIDRM, + EINPROGRESS = EINPROGRESS, + EINTR = EINTR, + EINVAL = EINVAL, + EIO = EIO, + EISCONN = EISCONN, + EISDIR = EISDIR, + ELOOP = ELOOP, + EMFILE = EMFILE, + EMLINK = EMLINK, + EMSGSIZE = EMSGSIZE, + EMULTIHOP = EMULTIHOP, + ENAMETOOLONG = ENAMETOOLONG, + ENETDOWN = ENETDOWN, + ENETRESET = ENETRESET, + ENETUNREACH = ENETUNREACH, + ENFILE = ENFILE, + ENOBUFS = ENOBUFS, + ENODATA = ENODATA, + ENODEV = ENODEV, + ENOENT = ENOENT, + ENOEXEC = ENOEXEC, + ENOLCK = ENOLCK, + ENOLINK = ENOLINK, + ENOMEM = ENOMEM, + ENOMSG = ENOMSG, + ENOPROTOOPT = ENOPROTOOPT, + ENOSPC = ENOSPC, + ENOSR = ENOSR, + ENOSTR = ENOSTR, + ENOSYS = ENOSYS, + ENOTCONN = ENOTCONN, + ENOTDIR = ENOTDIR, + ENOTEMPTY = ENOTEMPTY, + ENOTRECOVERABLE = ENOTRECOVERABLE, + ENOTSOCK = ENOTSOCK, + ENOTSUP = ENOTSUP, + ENOTTY = ENOTTY, + ENXIO = ENXIO, + EOPNOTSUPP = EOPNOTSUPP, + EOVERFLOW = EOVERFLOW, + EOWNERDEAD = EOWNERDEAD, + EPERM = EPERM, + EPIPE = EPIPE, + EPROTO = EPROTO, + EPROTONOSUPPORT = EPROTONOSUPPORT, + EPROTOTYPE = EPROTOTYPE, + EROFS = EROFS, + ESPIPE = ESPIPE, + ESRCH = ESRCH, + ESTALE = ESTALE, + ETIME = ETIME, + ETIMEDOUT = ETIMEDOUT, + ETXTBSY = ETXTBSY, + EWOULDBLOCK = EWOULDBLOCK, + EXDEV = EXDEV, +} + +when ODIN_OS == .Darwin { + EPERM :: 1 + ENOENT :: 2 + ESRCH :: 3 + EINTR :: 4 + EIO :: 5 + ENXIO :: 6 + E2BIG :: 7 + ENOEXEC :: 8 + EBADF :: 9 + ECHILD :: 10 + EDEADLK :: 11 + ENOMEM :: 12 + EACCES :: 13 + EFAULT :: 14 + EBUSY :: 16 + EEXIST :: 17 + EXDEV :: 18 + ENODEV :: 19 + ENOTDIR :: 20 + EISDIR :: 21 + EINVAL :: 22 + ENFILE :: 23 + EMFILE :: 24 + ENOTTY :: 25 + ETXTBSY :: 26 + EFBIG :: 27 + ENOSPC :: 28 + ESPIPE :: 29 + EROFS :: 30 + EMLINK :: 31 + EPIPE :: 32 + EAGAIN :: 35 + EWOULDBLOCK :: 35 + EINPROGRESS :: 36 + EALREADY :: 37 + ENOTSOCK :: 38 + EDESTADDRREQ :: 39 + EMSGSIZE :: 40 + EPROTOTYPE :: 41 + ENOPROTOOPT :: 42 + EPROTONOSUPPORT :: 43 + ENOTSUP :: 45 + EOPNOTSUPP :: 45 + EAFNOSUPPORT :: 47 + EADDRINUSE :: 48 + EADDRNOTAVAIL :: 49 + ENETDOWN :: 50 + ENETUNREACH :: 51 + ENETRESET :: 52 + ECONNABORTED :: 53 + ECONNRESET :: 54 + ENOBUFS :: 55 + EISCONN :: 56 + ENOTCONN :: 57 + ETIMEDOUT :: 60 + ECONNREFUSED :: 61 + ELOOP :: 62 + ENAMETOOLONG :: 63 + EHOSTUNREACH :: 65 + ENOTEMPTY :: 66 + EDQUOT :: 69 + ESTALE :: 70 + ENOLCK :: 77 + ENOSYS :: 78 + EOVERFLOW :: 84 + ECANCELED :: 89 + EIDRM :: 90 + ENOMSG :: 91 + EBADMSG :: 94 + EMULTIHOP :: 95 + ENODATA :: 96 + ENOLINK :: 97 + ENOSR :: 98 + ENOSTR :: 99 + EPROTO :: 100 + ETIME :: 101 + ENOTRECOVERABLE :: 104 + EOWNERDEAD :: 105 +} else when ODIN_OS == .FreeBSD { + EPERM :: 1 + ENOENT :: 2 + ESRCH :: 3 + EINTR :: 4 + EIO :: 5 + ENXIO :: 6 + E2BIG :: 7 + ENOEXEC :: 8 + EBADF :: 9 + ECHILD :: 10 + EDEADLK :: 11 + ENOMEM :: 12 + EACCES :: 13 + EFAULT :: 14 + EBUSY :: 16 + EEXIST :: 17 + EXDEV :: 18 + ENODEV :: 19 + ENOTDIR :: 20 + EISDIR :: 21 + EINVAL :: 22 + ENFILE :: 23 + EMFILE :: 24 + ENOTTY :: 25 + ETXTBSY :: 26 + EFBIG :: 27 + ENOSPC :: 28 + ESPIPE :: 29 + EROFS :: 30 + EMLINK :: 31 + EPIPE :: 32 + EAGAIN :: 35 + EWOULDBLOCK :: 35 + EINPROGRESS :: 36 + EALREADY :: 37 + ENOTSOCK :: 38 + EDESTADDRREQ :: 39 + EMSGSIZE :: 40 + EPROTOTYPE :: 41 + ENOPROTOOPT :: 42 + EPROTONOSUPPORT :: 43 + ENOTSUP :: 45 + EOPNOTSUPP :: 45 + EAFNOSUPPORT :: 47 + EADDRINUSE :: 48 + EADDRNOTAVAIL :: 49 + ENETDOWN :: 50 + ENETUNREACH :: 51 + ENETRESET :: 52 + ECONNABORTED :: 53 + ECONNRESET :: 54 + ENOBUFS :: 55 + EISCONN :: 56 + ENOTCONN :: 57 + ETIMEDOUT :: 60 + ECONNREFUSED :: 61 + ELOOP :: 62 + ENAMETOOLONG :: 63 + EHOSTUNREACH :: 65 + ENOTEMPTY :: 66 + EDQUOT :: 69 + ESTALE :: 70 + ENOLCK :: 77 + ENOSYS :: 78 + EOVERFLOW :: 84 + EIDRM :: 82 + ENOMSG :: 83 + ECANCELED :: 85 + EBADMSG :: 89 + EMULTIHOP :: 90 + ENOLINK :: 91 + EPROTO :: 92 + ENOTRECOVERABLE :: 95 + EOWNERDEAD :: 96 + + // NOTE: not defined for freebsd + ENODATA :: -1 + ENOSR :: -1 + ENOSTR :: -1 + ETIME :: -1 +} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + EPERM :: 1 + ENOENT :: 2 + ESRCH :: 3 + EINTR :: 4 + EIO :: 5 + ENXIO :: 6 + E2BIG :: 7 + ENOEXEC :: 8 + EBADF :: 9 + ECHILD :: 10 + EDEADLK :: 11 + ENOMEM :: 12 + EACCES :: 13 + EFAULT :: 14 + EBUSY :: 16 + EEXIST :: 17 + EXDEV :: 18 + ENODEV :: 19 + ENOTDIR :: 20 + EISDIR :: 21 + EINVAL :: 22 + ENFILE :: 23 + EMFILE :: 24 + ENOTTY :: 25 + ETXTBSY :: 26 + EFBIG :: 27 + ENOSPC :: 28 + ESPIPE :: 29 + EROFS :: 30 + EMLINK :: 31 + EPIPE :: 32 + EAGAIN :: 35 + EWOULDBLOCK :: 35 + EINPROGRESS :: 36 + EALREADY :: 37 + ENOTSOCK :: 38 + EDESTADDRREQ :: 39 + EMSGSIZE :: 40 + EPROTOTYPE :: 41 + ENOPROTOOPT :: 42 + EPROTONOSUPPORT :: 43 + ENOTSUP :: 45 + EOPNOTSUPP :: 45 + EAFNOSUPPORT :: 47 + EADDRINUSE :: 48 + EADDRNOTAVAIL :: 49 + ENETDOWN :: 50 + ENETUNREACH :: 51 + ENETRESET :: 52 + ECONNABORTED :: 53 + ECONNRESET :: 54 + ENOBUFS :: 55 + EISCONN :: 56 + ENOTCONN :: 57 + ETIMEDOUT :: 60 + ECONNREFUSED :: 61 + ELOOP :: 62 + ENAMETOOLONG :: 63 + EHOSTUNREACH :: 65 + ENOTEMPTY :: 66 + EDQUOT :: 69 + ESTALE :: 70 + ENOLCK :: 77 + ENOSYS :: 78 + + when ODIN_OS == .NetBSD { + EOVERFLOW :: 84 + EIDRM :: 82 + ENOMSG :: 83 + ECANCELED :: 87 + EBADMSG :: 88 + ENODATA :: 89 + EMULTIHOP :: 94 + ENOLINK :: 95 + EPROTO :: 96 + ENOTRECOVERABLE :: 98 + EOWNERDEAD :: 97 + ENOSR :: 90 + ENOSTR :: 91 + ETIME :: 92 + } else { + EOVERFLOW :: 87 + EIDRM :: 89 + ENOMSG :: 90 + ECANCELED :: 88 + EBADMSG :: 92 + EPROTO :: 95 + ENOTRECOVERABLE :: 93 + EOWNERDEAD :: 94 + // NOTE: not defined for openbsd + ENODATA :: -1 + EMULTIHOP :: -1 + ENOLINK :: -1 + ENOSR :: -1 + ENOSTR :: -1 + ETIME :: -1 + } + +} else { + #panic("posix is unimplemented for the current target") +} + diff --git a/core/sys/posix/fcntl.odin b/core/sys/posix/fcntl.odin new file mode 100644 index 000000000..436104613 --- /dev/null +++ b/core/sys/posix/fcntl.odin @@ -0,0 +1,415 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// fcntl.h - file control options + +foreign lib { + /* + Implemented as `return open(path, O_WRONLY|O_CREAT|O_TRUNC, mode);` + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/creat.html ]] + */ + creat :: proc(path: cstring, mode: mode_t) -> FD --- + + /* + Perform the operations on open files. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html ]] + */ + fcntl :: proc(fd: FD, cmd: FCNTL_Cmd, arg: rawptr = nil) -> c.int --- + + /* + Establish the connection between a file and a file descriptor. + It shall create an open file description that refers to a file and a file descriptor that + refers to that open file description. The file descriptor is used by other I/O functions to + refer to that file. + The path argument points to a pathname naming the file + + Returns: -1 on failure (setting errno), a file descriptor on success. + + Example: + // The following example opens the file /tmp/file, either by creating it (if it does not already exist), + // or by truncating its length to 0 (if it does exist). In the former case, if the call creates a new file, + // the access permission bits in the file mode of the file are set to permit reading and writing by the owner, + // and to permit reading only by group members and others. + fd := posix.open("/tmp/file", { .WRONLY, .CREAT, .TRUNC }, { .IRUSR, .IWUSR, .IRGRP, .IROTH }) + + // The following example uses the open() function to try to create the LOCKFILE file and open it for writing. + // Since the open() function specifies the O_EXCL flag, the call fails if the file already exists. + // In that case, the program assumes that someone else is updating the password file and exits. + fd := posix.open("/etc/ptmp", { .WRONLY, .CREAT, .EXCL }, { .IRUSR, .IWUSR, .IRGRP, .IROTH }) + if fd == -1 { + fmt.println("cannot open /etc/ptmp") + } + + // The following example opens a file for writing, creating the file if it does not already exist. + // If the file does exist, the system truncates the file to zero bytes. + fd := posix.open("/etc/ptmp", { .WRONLY, .CREAT, .TRUNC }, { .IRUSR, .IWUSR, .IRGRP, .IROTH }) + if fd == -1 { + fmt.println("cannot open output file") + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html ]] + */ + open :: proc(path: cstring, flags: O_Flags, mode: mode_t = {}) -> FD --- + + /* + Equivalent to the open() function except in the case where path specifies a relative path. + In this case the file to be opened is determined relative to the directory associated with the + file descriptor fd instead of the current working directory. + + Returns: -1 on failure (setting errno), a file descriptor on success. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html ]] + */ + openat :: proc(fd: FD, path: cstring, flags: O_Flags, mode: mode_t = {}) -> FD --- +} + +FCNTL_Cmd :: enum c.int { + DUPFD = F_DUPFD, + DUPFD_CLOEXEC = F_DUPFD_CLOEXEC, + GETFD = F_GETFD, + SETFD = F_SETFD, + GETFL = F_GETFL, + SETFL = F_SETFL, + GETLK = F_GETLK, + SETLK = F_SETLK, + SETLKW = F_SETLKW, + GETOWN = F_GETOWN, + SETOWN = F_SETOWN, +} + +Lock_Type :: enum c.short { + RDLCK = F_RDLCK, + UNLCK = F_UNLCK, + WRLCK = F_WRLCK, +} + +// Assertions made to unify this bit set. +#assert(O_RDONLY == 0) + +O_Flag_Bits :: enum c.int { + // Sets FD_CLOEXEC on the file descriptor. + CLOEXEC = log2(O_CLOEXEC), + // If not exists, combined with DIRECTORY will cause creation of a directory, otherwise a regular file. + CREAT = log2(O_CREAT), + // Fails if the opened descriptor would not be a directory. + DIRECTORY = log2(O_DIRECTORY), + // If combined with CREAT, causes a failure if the file already exists. + EXCL = log2(O_EXCL), + // If terminal device, do not make it the controlling terminal for the process. + NOCTTY = log2(O_NOCTTY), + // Don't follow symbolic links, fail with errno ELOOP. + NOFOLLOW = log2(O_NOFOLOW), + // If exists and regular, truncate the length to 0. + TRUNC = log2(O_TRUNC), + + // NOTE: use with `posix.O_TTY_INIT + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in + // this bit set enum because it is 0 on some platforms and a value on others. + // TTY_INIT = O_TTY_INIT, + + // Set file offset to end of file prior to each write. + APPEND = log2(O_APPEND), + // Write I/O shall complete as defined by synchronized I/O data integrity completion. + DSYNC = log2(O_DSYNC), + // Causes nonblocking behaviour in various situations. + NONBLOCK = log2(O_NONBLOCK), + // Write I/O shall complete as defined by synchronized I/O file integrity completion. + SYNC = log2(O_SYNC), + // NOTE: use with `posix.O_RSYNC + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in + // this bit set enum because it is 0 on some platforms and a value on others. + // RSYNC = O_RSYNC, + + // Execute only. + EXEC = log2(O_EXEC), + // Reading and writing. + RDWR = log2(O_RDWR), + // Writing only. + WRONLY = log2(O_WRONLY), + // Reading only. + // RDONLY = 0, // Default + +} +O_Flags :: bit_set[O_Flag_Bits; c.int] + +// A mask of all the access mode bits. +O_ACCMODE :: O_Flags{ .EXEC, .RDWR, .WRONLY } + +AT_Flag_Bits :: enum c.int { + EACCESS = log2(AT_EACCESS), + SYMLINK_NOFOLLOW = log2(AT_SYMLINK_NOFOLLOW), + SYMLINK_FOLLOW = log2(AT_SYMLINK_FOLLOW), + REMOVEDIR = log2(AT_REMOVEDIR), +} +AT_Flags :: bit_set[AT_Flag_Bits; c.int] + +when ODIN_OS == .Darwin { + + off_t :: distinct c.int64_t + pid_t :: distinct c.int32_t + + F_DUPFD :: 0 + F_DUPFD_CLOEXEC :: 67 + F_GETFD :: 1 + F_SETFD :: 2 + F_GETFL :: 3 + F_SETFL :: 4 + F_GETLK :: 7 + F_SETLK :: 8 + F_SETLKW :: 9 + F_GETOWN :: 5 + F_SETOWN :: 6 + + FD_CLOEXEC :: 1 + + F_RDLCK :: 1 + F_UNLCK :: 2 + F_WRLCK :: 3 + + O_CLOEXEC :: 0x01000000 + O_CREAT :: 0x00000200 + O_DIRECTORY :: 0x00100000 + O_EXCL :: 0x00000800 + O_NOCTTY :: 0x00020000 + O_NOFOLOW :: 0x00000100 + O_TRUNC :: 0x00000400 + + _O_TTY_INIT :: 0 + O_TTY_INIT :: O_Flags{} + + O_APPEND :: 0x00000008 + O_DSYNC :: 0x00400000 + O_NONBLOCK :: 0x00000004 + O_SYNC :: 0x0080 + + _O_RSYNC :: 0 + O_RSYNC :: O_Flags{} + + O_EXEC :: 0x40000000 + O_RDONLY :: 0 + O_RDWR :: 0x0002 + O_WRONLY :: 0x0001 + + _O_SEARCH :: O_EXEC | O_DIRECTORY + O_SEARCH :: O_Flags{ .EXEC, .DIRECTORY } + + AT_FDCWD: FD: -2 + + AT_EACCESS :: 0x0010 + AT_SYMLINK_NOFOLLOW :: 0x0020 + AT_SYMLINK_FOLLOW :: 0x0040 + AT_REMOVEDIR :: 0x0080 + + flock :: struct { + l_start: off_t, /* [PSX] relative offset in bytes */ + l_len: off_t, /* [PSX] size; if 0 then until EOF */ + l_pid: pid_t, /* [PSX] process ID of the process holding the lock */ + l_type: Lock_Type, /* [PSX] type of lock */ + l_whence: c.short, /* [PSX] flag (Whence) of starting offset */ + } + +} else when ODIN_OS == .FreeBSD { + + off_t :: distinct c.int64_t + pid_t :: distinct c.int32_t + + F_DUPFD :: 0 + F_DUPFD_CLOEXEC :: 17 + F_GETFD :: 1 + F_SETFD :: 2 + F_GETFL :: 3 + F_SETFL :: 4 + F_GETLK :: 7 + F_SETLK :: 8 + F_SETLKW :: 9 + F_GETOWN :: 5 + F_SETOWN :: 6 + + FD_CLOEXEC :: 1 + + F_RDLCK :: 1 + F_UNLCK :: 2 + F_WRLCK :: 3 + + O_CLOEXEC :: 0x00100000 + O_CREAT :: 0x0200 + O_DIRECTORY :: 0x00020000 + O_EXCL :: 0x0800 + O_NOCTTY :: 0x8000 + O_NOFOLOW :: 0x0100 + O_TRUNC :: 0x0400 + + _O_TTY_INIT :: 0x00080000 + O_TTY_INIT :: O_Flags{O_Flag_Bits(log2(_O_TTY_INIT))} + + O_APPEND :: 0x0008 + O_DSYNC :: 0x01000000 + O_NONBLOCK :: 0x0004 + O_SYNC :: 0x0080 + _O_RSYNC :: 0 + O_RSYNC :: O_Flags{} + + O_EXEC :: 0x00040000 + O_RDONLY :: 0 + O_RDWR :: 0x0002 + O_WRONLY :: 0x0001 + + _O_SEARCH :: O_EXEC|O_DIRECTORY + O_SEARCH :: O_Flags{ .EXEC, .DIRECTORY } + + AT_FDCWD: FD: -100 + + AT_EACCESS :: 0x0100 + AT_SYMLINK_NOFOLLOW :: 0x0200 + AT_SYMLINK_FOLLOW :: 0x0400 + AT_REMOVEDIR :: 0x0800 + + flock :: struct { + l_start: off_t, /* [PSX] relative offset in bytes */ + l_len: off_t, /* [PSX] size; if 0 then until EOF */ + l_pid: pid_t, /* [PSX] process ID of the process holding the lock */ + l_type: Lock_Type, /* [PSX] type of lock */ + l_whence: c.short, /* [PSX] flag (Whence) of starting offset */ + l_sysid: c.int, + } + +} else when ODIN_OS == .NetBSD { + + off_t :: distinct c.int64_t + pid_t :: distinct c.int32_t + + F_DUPFD :: 0 + F_DUPFD_CLOEXEC :: 12 + F_GETFD :: 1 + F_SETFD :: 2 + F_GETFL :: 3 + F_SETFL :: 4 + F_GETLK :: 7 + F_SETLK :: 8 + F_SETLKW :: 9 + F_GETOWN :: 5 + F_SETOWN :: 6 + + FD_CLOEXEC :: 1 + + F_RDLCK :: 1 + F_UNLCK :: 2 + F_WRLCK :: 3 + + O_CLOEXEC :: 0x00400000 + O_CREAT :: 0x0200 + O_DIRECTORY :: 0x0020000 + O_EXCL :: 0x0800 + O_NOCTTY :: 0x8000 + O_NOFOLOW :: 0x0100 + O_TRUNC :: 0x0400 + + _O_TTY_INIT :: 0 + O_TTY_INIT :: O_Flags{} // NOTE: not defined in the headers + + O_APPEND :: 0x0008 + O_DSYNC :: 0x010000 + O_NONBLOCK :: 0x0004 + O_SYNC :: 0x0080 + + _O_RSYNC :: 0x0002 + O_RSYNC :: O_Flags{O_Flag_Bits(log2(_O_RSYNC))} + + + O_EXEC :: 0x04000000 + O_RDONLY :: 0 + O_RDWR :: 0x0002 + O_WRONLY :: 0x0001 + + _O_SEARCH :: 0x00800000 + O_SEARCH :: O_Flags{O_Flag_Bits(log2(_O_SEARCH))} + + AT_FDCWD: FD: -100 + + AT_EACCESS :: 0x100 + AT_SYMLINK_NOFOLLOW :: 0x200 + AT_SYMLINK_FOLLOW :: 0x400 + AT_REMOVEDIR :: 0x800 + + flock :: struct { + l_start: off_t, /* [PSX] relative offset in bytes */ + l_len: off_t, /* [PSX] size; if 0 then until EOF */ + l_pid: pid_t, /* [PSX] process ID of the process holding the lock */ + l_type: Lock_Type, /* [PSX] type of lock */ + l_whence: c.short, /* [PSX] flag (Whence) of starting offset */ + } +} else when ODIN_OS == .OpenBSD { + + off_t :: distinct c.int64_t + pid_t :: distinct c.int32_t + + F_DUPFD :: 0 + F_DUPFD_CLOEXEC :: 10 + F_GETFD :: 1 + F_SETFD :: 2 + F_GETFL :: 3 + F_SETFL :: 4 + F_GETLK :: 7 + F_SETLK :: 8 + F_SETLKW :: 9 + F_GETOWN :: 5 + F_SETOWN :: 6 + + FD_CLOEXEC :: 1 + + F_RDLCK :: 1 + F_UNLCK :: 2 + F_WRLCK :: 3 + + O_CLOEXEC :: 0x10000 + O_CREAT :: 0x0200 + O_DIRECTORY :: 0x20000 + O_EXCL :: 0x0800 + O_NOCTTY :: 0x8000 + O_NOFOLOW :: 0x0100 + O_TRUNC :: 0x0400 + + _O_TTY_INIT :: 0 + O_TTY_INIT :: O_Flags{} // NOTE: not defined in the headers + + O_APPEND :: 0x0008 + O_DSYNC :: 0x010000 + O_NONBLOCK :: 0x0004 + O_SYNC :: 0x0080 + + _O_RSYNC :: O_SYNC + O_RSYNC :: O_Flags{ .SYNC } + + O_EXEC :: 0x04000000 // NOTE: not defined in the headers + O_RDONLY :: 0 + O_RDWR :: 0x0002 + O_WRONLY :: 0x0001 + + _O_SEARCH :: 0 + O_SEARCH :: O_Flags{} // NOTE: not defined in the headers + + AT_FDCWD: FD: -100 + + AT_EACCESS :: 0x01 + AT_SYMLINK_NOFOLLOW :: 0x02 + AT_SYMLINK_FOLLOW :: 0x04 + AT_REMOVEDIR :: 0x08 + + flock :: struct { + l_start: off_t, /* [PSX] relative offset in bytes */ + l_len: off_t, /* [PSX] size; if 0 then until EOF */ + l_pid: pid_t, /* [PSX] process ID of the process holding the lock */ + l_type: Lock_Type, /* [PSX] type of lock */ + l_whence: c.short, /* [PSX] flag (Whence) of starting offset */ + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/fnmatch.odin b/core/sys/posix/fnmatch.odin new file mode 100644 index 000000000..9e54972e7 --- /dev/null +++ b/core/sys/posix/fnmatch.odin @@ -0,0 +1,58 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// fnmatch.h - filename-matching types + +foreign lib { + /* + Match patterns as described in XCU [[ Patterns Matching a Single Character; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_01 ]] + // and [[ Patterns Matching Multiple Characters; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_02 ]]. + It checks the string specified by the string argument to see if it matches the pattern specified by the pattern argument. + + Returns: 0 when matched. if there is no match, fnmatch() shall return FNM_NOMATCH. Non-zero on other errors. + + Example: + assert(posix.fnmatch("*.odin", "foo.odin", {}) == 0) + assert(posix.fnmatch("*.txt", "foo.odin", {}) == posix.FNM_NOMATCH) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html ]] + */ + fnmatch :: proc(pattern: cstring, string: cstring, flags: FNM_Flags) -> c.int --- +} + +FNM_Flag_Bits :: enum c.int { + // A character ( '/' ) in string shall be explicitly matched by a in pattern; + // it shall not be matched by either the or special characters, + // nor by a bracket expression. + PATHNAME = log2(FNM_PATHNAME), + + // A leading ( '.' ) in string shall match a in pattern; + // as described by rule 2 in XCU [[ Patterns Used for Filename Expansion; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_03 ]] + // where the location of "leading" is indicated by the value of PATHNAME: + // 1. If PATHNAME is set, a is "leading" if it is the first character in string or if it immediately follows a . + // 2. If PATHNAME is not set, a is "leading" only if it is the first character of string. + PERIOD = log2(FNM_PERIOD), + + // A character shall be treated as an ordinary character. + NOESCAPE = log2(FNM_NOESCAPE), +} +FNM_Flags :: bit_set[FNM_Flag_Bits; c.int] + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + FNM_NOMATCH :: 1 + + FNM_PATHNAME :: 0x02 + FNM_PERIOD :: 0x04 + FNM_NOESCAPE :: 0x01 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/glob.odin b/core/sys/posix/glob.odin new file mode 100644 index 000000000..4f41d83db --- /dev/null +++ b/core/sys/posix/glob.odin @@ -0,0 +1,179 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// glob.h - pathname pattern-matching types + +foreign lib { + /* + The glob() function is a pathname generator that shall implement the rules defined in + [[ XCU Pattern Matching Notation; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13 ]], + with optional support for rule 3 in XCU [[ Patterns Used for Filename Expansion; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_03 ]]. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/glob.html ]] + */ + @(link_name=LGLOB) + glob :: proc( + pattern: cstring, + flags: Glob_Flags, + errfunc: proc "c" (epath: cstring, eerrno: Errno) -> b32 = nil, // Return `true` to abort the glob(). + pglob: ^glob_t, + ) -> Glob_Result --- + + /* + Free the glob results. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/glob.html ]] + */ + @(link_name=LGLOBFREE) + globfree :: proc(^glob_t) --- +} + +Glob_Flag_Bits :: enum c.int { + // Append pathnames generated to the ones from a previous call to glob(). + APPEND = log2(GLOB_APPEND), + // Make use of pglob->gl_offs. If this flag is set, pglob->gl_offs is used to specify how many null pointers to add to the beginning of pglob->gl_pathv. + // In other words, pglob->gl_pathv shall point to pglob->gl_offs null pointers, followed by pglob->gl_pathc pathname pointers, followed by a null pointer. + DOOFFS = log2(GLOB_DOOFFS), + // Cause glob() to return when it encounters a directory that it cannot open or read. Ordinarily, + // glob() continues to find matches. + ERR = log2(GLOB_ERR), + // Each pathname that is a directory that matches pattern shall have a appended. + MARK = log2(GLOB_MARK), + // Supports rule 3 in [[ XCU Patterns Used for Filename Expansion; https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_03 ]]. + // If pattern does not match any pathname, then glob() shall return a list consisting of only pattern, + // and the number of matched pathnames is 1. + NOCHECK = log2(GLOB_NOCHECK), + // Disable backslash escaping. + NOESCAPE = log2(GLOB_NOESCAPE), + // Ordinarily, glob() sorts the matching pathnames according to the current setting of the + // LC_COLLATE category; see XBD LC_COLLATE. When this flag is used, + // the order of pathnames returned is unspecified. + NOSORT = log2(GLOB_NOSORT), +} +Glob_Flags :: bit_set[Glob_Flag_Bits; c.int] + +Glob_Result :: enum c.int { + SUCCESS = 0, + ABORTED = GLOB_ABORTED, + NOMATCH = GLOB_NOMATCH, + NOSPACE = GLOB_NOSPACE, +} + +when ODIN_OS == .NetBSD { + @(private) LGLOB :: "__glob30" + @(private) LGLOBFREE :: "__globfree30" +} else { + @(private) LGLOB :: "glob" + INODE_SUFFIX + @(private) LGLOBFREE :: "globfree" +} + +when ODIN_OS == .Darwin { + + glob_t :: struct { + gl_pathc: c.size_t, /* [PSX] count of paths matched by pattern */ + gl_matchc: c.int, /* count of paths matching pattern */ + gl_offs: c.size_t, /* [PSX] slots to reserve at the beginning of gl_pathv */ + gl_flags: Glob_Flags, /* copy of flags parameter to glob */ + gl_pathv: [^]cstring `fmt:"v,gl_pathc"`, /* [PSX] pointer to list of matched pathnames */ + + // Non-standard alternate file system access functions: + + using _: struct #raw_union { + gl_errfunc: proc "c" (cstring, c.int) -> c.int, + gl_errblk: proc "c" (cstring, c.int) -> c.int, + }, + gl_closedir: proc "c" (dirp: DIR), + gl_readdir: proc "c" (dirp: DIR) -> ^dirent, + gl_opendir: proc "c" (path: cstring) -> DIR, + gl_lstat: proc "c" (path: cstring, buf: ^stat_t) -> result, + gl_stat: proc "c" (path: cstring, buf: ^stat_t) -> result, + } + + GLOB_APPEND :: 0x0001 + GLOB_DOOFFS :: 0x0002 + GLOB_ERR :: 0x0004 + GLOB_MARK :: 0x0008 + GLOB_NOCHECK :: 0x0010 + GLOB_NOESCAPE :: 0x2000 + GLOB_NOSORT :: 0x0020 + + GLOB_ABORTED :: -2 + GLOB_NOMATCH :: -3 + GLOB_NOSPACE :: -1 + +} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD { + + glob_t :: struct { + gl_pathc: c.size_t, /* [PSX] count of paths matched by pattern */ + gl_matchc: c.size_t, /* count of paths matching pattern */ + gl_offs: c.size_t, /* [PSX] slots to reserve at the beginning of gl_pathv */ + gl_flags: Glob_Flags, /* copy of flags parameter to glob */ + gl_pathv: [^]cstring `fmt:"v,gl_pathc"`, /* [PSX] pointer to list of matched pathnames */ + + // Non-standard alternate file system access functions: + + gl_errfunc: proc "c" (cstring, c.int) -> c.int, + + gl_closedir: proc "c" (dirp: DIR), + gl_readdir: proc "c" (dirp: DIR) -> ^dirent, + gl_opendir: proc "c" (path: cstring) -> DIR, + gl_lstat: proc "c" (path: cstring, buf: ^stat_t) -> result, + gl_stat: proc "c" (path: cstring, buf: ^stat_t) -> result, + } + + GLOB_APPEND :: 0x0001 + GLOB_DOOFFS :: 0x0002 + GLOB_ERR :: 0x0004 + GLOB_MARK :: 0x0008 + GLOB_NOCHECK :: 0x0010 + GLOB_NOESCAPE :: 0x2000 when ODIN_OS == .FreeBSD else 0x0100 + GLOB_NOSORT :: 0x0020 + + GLOB_ABORTED :: -2 + GLOB_NOMATCH :: -3 + GLOB_NOSPACE :: -1 + +} else when ODIN_OS == .OpenBSD { + + glob_t :: struct { + gl_pathc: c.size_t, /* [PSX] count of paths matched by pattern */ + gl_matchc: c.size_t, /* count of paths matching pattern */ + gl_offs: c.size_t, /* [PSX] slots to reserve at the beginning of gl_pathv */ + gl_flags: Glob_Flags, /* copy of flags parameter to glob */ + gl_pathv: [^]cstring `fmt:"v,gl_pathc"`, /* [PSX] pointer to list of matched pathnames */ + + gl_statv: [^]stat_t, + + // Non-standard alternate file system access functions: + + gl_errfunc: proc "c" (cstring, c.int) -> c.int, + + gl_closedir: proc "c" (dirp: DIR), + gl_readdir: proc "c" (dirp: DIR) -> ^dirent, + gl_opendir: proc "c" (path: cstring) -> DIR, + gl_lstat: proc "c" (path: cstring, buf: ^stat_t) -> result, + gl_stat: proc "c" (path: cstring, buf: ^stat_t) -> result, + } + + GLOB_APPEND :: 0x0001 + GLOB_DOOFFS :: 0x0002 + GLOB_ERR :: 0x0004 + GLOB_MARK :: 0x0008 + GLOB_NOCHECK :: 0x0010 + GLOB_NOESCAPE :: 0x1000 + GLOB_NOSORT :: 0x0020 + + GLOB_ABORTED :: -2 + GLOB_NOMATCH :: -3 + GLOB_NOSPACE :: -1 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/grp.odin b/core/sys/posix/grp.odin new file mode 100644 index 000000000..c8a39de6a --- /dev/null +++ b/core/sys/posix/grp.odin @@ -0,0 +1,130 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// grp.h - group structure + +foreign lib { + /* + Closes the group database. + + Checking status would be done by setting errno to 0, calling this, and checking errno. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/endgrent.html ]] + */ + endgrent :: proc() --- + + /* + Rewinds the group database so getgrent() returns the first entry again. + + Checking status would be done by setting errno to 0, calling this, and checking errno. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/endgrent.html ]] + */ + setgrent :: proc() --- + + /* + Returns a pointer to an entry of the group database. + + Opens the group database if it isn't. + + Returns: nil on failure (setting errno) or EOF (not setting errno), the entry otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/endgrent.html ]] + */ + getgrent :: proc() -> ^group --- + + /* + Searches for an entry with a matching gid in the group database. + + Returns: nil (setting errno) on failure, a pointer to the entry on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgrgid.html ]] + */ + getgrgid :: proc(gid: gid_t) -> ^group --- + + /* + Searches for an entry with a matching gid in the group database. + + Updates grp with the matching entry and stores it (or a nil pointer (setting errno)) into result. + + Strings are allocated into the given buffer, you can call `sysconf(._GETGR_R_SIZE_MAX)` for an appropriate size. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgrgid.html ]] + */ + getgrgid_r :: proc(gid: gid_t, grp: ^group, buffer: [^]byte, bufsize: c.size_t, result: ^^group) -> Errno --- + + /* + Searches for an entry with a matching gid in the group database. + + Returns: nil (setting errno) on failure, a pointer to the entry on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgrnam.html ]] + */ + getgrnam :: proc(name: cstring) -> ^group --- + + /* + Searches for an entry with a matching gid in the group database. + + Updates grp with the matching entry and stores it (or a nil pointer (setting errno)) into result. + + Strings are allocated into the given buffer, you can call `sysconf(._GETGR_R_SIZE_MAX)` for an appropriate size. + + Example: + length := posix.sysconf(._GETGR_R_SIZE_MAX) + if length == -1 { + length = 1024 + } + + result: posix.group + resultp: ^posix.group + + e: posix.Errno + + buffer: [dynamic]byte + defer delete(buffer) + + for { + mem_err := resize(&buffer, length) + assert(mem_err == nil) + + e = posix.getgrnam_r("nobody", &result, raw_data(buffer), len(buffer), &resultp) + if e != .ERANGE { + break + } + + length *= 2 + assert(length > 0) + } + + if e != .NONE { + panic(string(posix.strerror(e))) + } + + fmt.println(result) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgrnam.html ]] + */ + getgrnam_r :: proc(name: cstring, grp: ^group, buffer: [^]byte, bufsize: c.size_t, result: ^^group) -> Errno --- +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + gid_t :: distinct c.uint32_t + + group :: struct { + gr_name: cstring, /* [PSX] group name */ + gr_passwd: cstring, /* group password */ + gr_gid: gid_t, /* [PSX] group id */ + gr_mem: [^]cstring, /* [PSX] group members */ + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/iconv.odin b/core/sys/posix/iconv.odin new file mode 100644 index 000000000..59248890f --- /dev/null +++ b/core/sys/posix/iconv.odin @@ -0,0 +1,50 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + // NOTE: iconv is in a different library + foreign import lib "system:iconv" +} else { + foreign import lib "system:c" +} + +// iconv.h - codeset conversion facility + +iconv_t :: distinct rawptr + +foreign lib { + /* + Convert the sequence of characters from one codeset, in the array specified by inbuf, + into a sequence of corresponding characters in another codeset, in the array specified by outbuf. + + Returns: -1 (setting errno) on failure, the number of non-identical conversions performed on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/iconv.html ]] + */ + iconv :: proc( + cd: iconv_t, + inbuf: ^[^]byte, + inbytesleft: ^c.size_t, + outbuf: ^[^]byte, + outbyteslen: ^c.size_t, + ) -> c.size_t --- + + /* + Deallocates the conversion descriptor cd and all other associated resources allocated by iconv_open(). + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/iconv_close.html ]] + */ + iconv_close :: proc(cd: iconv_t) -> result --- + + /* + Returns a conversion descriptor that describes a conversion from the codeset specified by the + string pointed to by the fromcode argument to the codeset specified by the string pointed to by + the tocode argument. + + Returns: -1 (setting errno) on failure, a conversion descriptor on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/iconv_open.html ]] + */ + iconv_open :: proc(tocode: cstring, fromcode: cstring) -> iconv_t --- +} diff --git a/core/sys/posix/langinfo.odin b/core/sys/posix/langinfo.odin new file mode 100644 index 000000000..24ecc917a --- /dev/null +++ b/core/sys/posix/langinfo.odin @@ -0,0 +1,285 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// langinfo.h - language information constants + +foreign lib { + /* + Return a pointer to a string containing information relevant to the particular language or + cultural area defined in the current locale. + + Returns: a string that should not be freed or modified, and that can be invalidated at any time later + + Example: + for item in posix.nl_item { + fmt.printfln("%v: %q", item, posix.nl_langinfo(item)) + } + + Possible Output: + CODESET: "US-ASCII" + D_T_FMT: "%a %b %e %H:%M:%S %Y" + D_FMT: "%m/%d/%y" + T_FMT: "%H:%M:%S" + T_FMT_AMPM: "%I:%M:%S %p" + AM_STR: "AM" + PM_STR: "PM" + DAY_1: "Sunday" + DAY_2: "Monday" + DAY_3: "Tuesday" + DAY_4: "Wednesday" + DAY_5: "Thursday" + DAY_6: "Friday" + DAY_7: "Saturday" + ABDAY_1: "Sun" + ABDAY_2: "Mon" + ABDAY_3: "Tue" + ABDAY_4: "Wed" + ABDAY_5: "Thu" + ABDAY_6: "Fri" + ABDAY_7: "Sat" + MON_1: "January" + MON_2: "February" + MON_3: "March" + MON_4: "April" + MON_5: "May" + MON_6: "June" + MON_7: "July" + MON_8: "August" + MON_9: "September" + MON_10: "October" + MON_11: "November" + MON_12: "December" + ABMON_1: "Jan" + ABMON_2: "Feb" + ABMON_3: "Mar" + ABMON_4: "Apr" + ABMON_5: "May" + ABMON_6: "Jun" + ABMON_7: "Jul" + ABMON_8: "Aug" + ABMON_9: "Sep" + ABMON_10: "Oct" + ABMON_11: "Nov" + ABMON_12: "Dec" + ERA: "" + ERA_D_FMT: "" + ERA_D_T_FMT: "" + ERA_T_FMT: "" + ALT_DIGITS: "" + RADIXCHAR: "." + THOUSEP: "" + YESEXPR: "^[yY]" + NOEXPR: "^[nN]" + CRNCYSTR: "" + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/nl_langinfo.html ]] + */ + nl_langinfo :: proc(nl_item) -> cstring --- +} + +nl_item :: enum nl_item_t { + CODESET = CODESET, + D_T_FMT = D_T_FMT, + D_FMT = D_FMT, + T_FMT = T_FMT, + T_FMT_AMPM = T_FMT_AMPM, + AM_STR = AM_STR, + PM_STR = PM_STR, + DAY_1 = DAY_1, + DAY_2 = DAY_2, + DAY_3 = DAY_3, + DAY_4 = DAY_4, + DAY_5 = DAY_5, + DAY_6 = DAY_6, + DAY_7 = DAY_7, + ABDAY_1 = ABDAY_1, + ABDAY_2 = ABDAY_2, + ABDAY_3 = ABDAY_3, + ABDAY_4 = ABDAY_4, + ABDAY_5 = ABDAY_5, + ABDAY_6 = ABDAY_6, + ABDAY_7 = ABDAY_7, + MON_1 = MON_1, + MON_2 = MON_2, + MON_3 = MON_3, + MON_4 = MON_4, + MON_5 = MON_5, + MON_6 = MON_6, + MON_7 = MON_7, + MON_8 = MON_8, + MON_9 = MON_9, + MON_10 = MON_10, + MON_11 = MON_11, + MON_12 = MON_12, + ABMON_1 = ABMON_1, + ABMON_2 = ABMON_2, + ABMON_3 = ABMON_3, + ABMON_4 = ABMON_4, + ABMON_5 = ABMON_5, + ABMON_6 = ABMON_6, + ABMON_7 = ABMON_7, + ABMON_8 = ABMON_8, + ABMON_9 = ABMON_9, + ABMON_10 = ABMON_10, + ABMON_11 = ABMON_11, + ABMON_12 = ABMON_12, + ERA = ERA, + ERA_D_FMT = ERA_D_FMT, + ERA_D_T_FMT = ERA_D_T_FMT, + ERA_T_FMT = ERA_T_FMT, + ALT_DIGITS = ALT_DIGITS, + RADIXCHAR = RADIXCHAR, + THOUSEP = THOUSEP, + YESEXPR = YESEXPR, + NOEXPR = NOEXPR, + CRNCYSTR = CRNCYSTR, +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD { + + // NOTE: declared with `_t` so we can enumerate the real `nl_info`. + nl_item_t :: distinct c.int + + CODESET :: 0 + D_T_FMT :: 1 + D_FMT :: 2 + T_FMT :: 3 + T_FMT_AMPM :: 4 + AM_STR :: 5 + PM_STR :: 6 + + DAY_1 :: 7 + DAY_2 :: 8 + DAY_3 :: 9 + DAY_4 :: 10 + DAY_5 :: 11 + DAY_6 :: 12 + DAY_7 :: 13 + + ABDAY_1 :: 14 + ABDAY_2 :: 15 + ABDAY_3 :: 16 + ABDAY_4 :: 17 + ABDAY_5 :: 18 + ABDAY_6 :: 19 + ABDAY_7 :: 20 + + MON_1 :: 21 + MON_2 :: 22 + MON_3 :: 23 + MON_4 :: 24 + MON_5 :: 25 + MON_6 :: 26 + MON_7 :: 27 + MON_8 :: 28 + MON_9 :: 29 + MON_10 :: 30 + MON_11 :: 31 + MON_12 :: 32 + + ABMON_1 :: 33 + ABMON_2 :: 34 + ABMON_3 :: 35 + ABMON_4 :: 36 + ABMON_5 :: 37 + ABMON_6 :: 38 + ABMON_7 :: 39 + ABMON_8 :: 40 + ABMON_9 :: 41 + ABMON_10 :: 42 + ABMON_11 :: 43 + ABMON_12 :: 44 + + ERA :: 45 + ERA_D_FMT :: 46 + ERA_D_T_FMT :: 47 + ERA_T_FMT :: 48 + ALT_DIGITS :: 49 + + RADIXCHAR :: 50 + THOUSEP :: 51 + + YESEXPR :: 52 + NOEXPR :: 53 + + CRNCYSTR :: 56 + +} else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + // NOTE: declared with `_t` so we can enumerate the real `nl_info`. + nl_item_t :: distinct c.int + + CODESET :: 51 + D_T_FMT :: 0 + D_FMT :: 1 + T_FMT :: 2 + T_FMT_AMPM :: 3 + AM_STR :: 4 + PM_STR :: 5 + + DAY_1 :: 6 + DAY_2 :: 7 + DAY_3 :: 8 + DAY_4 :: 9 + DAY_5 :: 10 + DAY_6 :: 11 + DAY_7 :: 12 + + ABDAY_1 :: 13 + ABDAY_2 :: 14 + ABDAY_3 :: 15 + ABDAY_4 :: 16 + ABDAY_5 :: 17 + ABDAY_6 :: 18 + ABDAY_7 :: 19 + + MON_1 :: 20 + MON_2 :: 21 + MON_3 :: 22 + MON_4 :: 23 + MON_5 :: 24 + MON_6 :: 25 + MON_7 :: 26 + MON_8 :: 27 + MON_9 :: 28 + MON_10 :: 29 + MON_11 :: 30 + MON_12 :: 31 + + ABMON_1 :: 32 + ABMON_2 :: 33 + ABMON_3 :: 34 + ABMON_4 :: 35 + ABMON_5 :: 36 + ABMON_6 :: 37 + ABMON_7 :: 38 + ABMON_8 :: 39 + ABMON_9 :: 40 + ABMON_10 :: 41 + ABMON_11 :: 42 + ABMON_12 :: 43 + + ERA :: 52 + ERA_D_FMT :: 53 + ERA_D_T_FMT :: 54 + ERA_T_FMT :: 55 + ALT_DIGITS :: 56 + + RADIXCHAR :: 44 + THOUSEP :: 45 + + YESEXPR :: 47 + NOEXPR :: 49 + + CRNCYSTR :: 50 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/libgen.odin b/core/sys/posix/libgen.odin new file mode 100644 index 000000000..99506797e --- /dev/null +++ b/core/sys/posix/libgen.odin @@ -0,0 +1,74 @@ +package posix + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// libgen.h - definitions for pattern matching functions + +foreign lib { + /* + Takes the pathname pointed to by path and return a pointer to the final component of the + pathname, deleting any trailing '/' characters. + + NOTE: may modify input, so don't give it string literals. + + Returns: a string that might be a modification of the input string or a static string overwritten by subsequent calls + + Example: + tests := []string{ + "usr", "usr/", "", "/", "//", "///", "/usr/", "/usr/lib", + "//usr//lib//", "/home//dwc//test", + } + + tbl: table.Table + table.init(&tbl) + table.header(&tbl, "input", "dirname", "basename") + + for test in tests { + din := strings.clone_to_cstring(test); defer delete(din) + dir := strings.clone_from_cstring(posix.dirname(din)) + + bin := strings.clone_to_cstring(test); defer delete(bin) + base := strings.clone_from_cstring(posix.basename(bin)) + table.row(&tbl, test, dir, base) + } + + table.write_plain_table(os.stream_from_handle(os.stdout), &tbl) + + Output: + +----------------+----------+--------+ + |input |dirname |basename| + +----------------+----------+--------+ + |usr |. |usr | + |usr/ |. |usr | + | |. |. | + |/ |/ |/ | + |// |/ |/ | + |/// |/ |/ | + |/usr/ |/ |usr | + |/usr/lib |/usr |lib | + |//usr//lib// |//usr |lib | + |/home//dwc//test|/home//dwc|test | + +----------------+----------+--------+ + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/basename.html ]] + */ + basename :: proc(path: cstring) -> cstring --- + + /* + Takes a string that contains a pathname, and returns a string that is a pathname of the parent + directory of that file. + + NOTE: may modify input, so don't give it string literals. + + Returns: a string that might be a modification of the input string or a static string overwritten by subsequent calls + + See example for basename(). + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dirname.html ]] + */ + dirname :: proc(path: cstring) -> cstring --- +} diff --git a/core/sys/posix/limits.odin b/core/sys/posix/limits.odin new file mode 100644 index 000000000..7bb561215 --- /dev/null +++ b/core/sys/posix/limits.odin @@ -0,0 +1,459 @@ +package posix + +// limits.h - implementation-defined constants + +// NOTE: numerical limits are left out because Odin provides `min(T)` and `max(T)`. + +// The header shall define the following symbolic constants with the values shown. +// These are the most restrictive values for certain features on an implementation. +// A conforming implementation shall provide values no larger than these values. +// A conforming application must not require a smaller value for correct operation. + +_POSIX_CLOCKRES_MIN :: 20000000 + +// The header shall define the following symbolic constants with the values shown. +// These are the most restrictive values for certain features on an implementation conforming to +// this volume of POSIX.1-2017. +// Related symbolic constants are defined elsewhere in this volume of POSIX.1-2017 which reflect +// the actual implementation and which need not be as restrictive. For each of these limits, +// a conforming implementation shall provide a value at least this large or shall have no limit. +// A strictly conforming application must not require a larger value for correct operation. + +_POSIX_AIO_LISTIO_MAX :: 2 +_POSIX_AIO_MAX :: 1 +_POSIX_ARG_MAX :: 4096 +_POSIX_CHILD_MAX :: 25 +_POSIX_DELAYTIMER_MAX :: 32 +_POSIX_HOST_NAME_MAX :: 255 +_POSIX_LINK_MAX :: 8 +_POSIX_MAX_CANON :: 255 +_POSIX_MAX_INPUT :: 255 +_POSIX_MQ_OPEN_MAX :: 8 +_POSIX_MQ_PRIO_MAX :: 32 +_POSIX_NAME_MAX :: 14 +_POSIX_NGROUPS_MAX :: 8 +_POSIX_OPEN_MAX :: 20 +_POSIX_PATH_MAX :: 256 +_POSIX_PIPE_BUF :: 512 +_POSIX_RE_DUP_MAX :: 255 +_POSIX_RTSIG_MAX :: 8 +_POSIX_SEM_NSEMS_MAX :: 256 +_POSIX_SEM_VALUE_MAX :: 32767 +_POSIX_SS_REPL_MAX :: 4 +_POSIX_STREAM_MAX :: 8 +_POSIX_SYMLINK_MAX :: 255 +_POSIX_SYMLOOP_MAX :: 8 +_POSIX_THREAD_DESTRUCTION_ITERATIONS :: 4 +_POSIX_THREAD_KEYS_MAX :: 128 +_POSIX_THREADS_THREADS_MAX :: 64 +_POSIX_TIMER_MAX :: 32 +_POSIX_TRAXE_EVENT_NAME_MAX :: 30 +_POSIX_TRACE_NAME_MAX :: 8 +_POSIX_TRACE_SYS_MAX :: 8 +_POSIX_TRACE_USER_EVENT_MAX :: 32 +_POSIX_TTY_NAME_MAX :: 9 +_POSIX_TZNAME_MAX :: 6 +_POSIX2_BC_BASE_MAX :: 99 +_POSIX2_BC_DIM_MAX :: 2048 +_POSIX2_BC_SCALE_MAX :: 99 +_POSIX2_CHARCLASS_NAME_MAX :: 14 +_POSIX2_COLL_WEIGHTS_MAX :: 2 +_POSIX2_EXPR_NEST_MAX :: 32 +_POSIX2_LINE_MAX :: 2048 +_POSIX2_RE_DUP_MAX :: 255 +_XOPEN_IOV_MAX :: 16 +_XOPEN_NAME_MAX :: 255 +_XOPEN_PATH_MAX :: 1024 + +/* +NOTE: for full portability, usage should look something like: + + page_size: uint + when #defined(posix.PAGESIZE) { + page_size = posix.PAGESIZE + } else { + page_size = posix.sysconf(._PAGESIZE) + } +*/ + +when ODIN_OS == .Darwin { + // A definition of one of the symbolic constants in the following list shall be omitted from + // on specific implementations where the corresponding value is equal to or greater + // than the stated minimum, but is unspecified. + // + // This indetermination might depend on the amount of available memory space on a specific + // instance of a specific implementation. The actual value supported by a specific instance shall + // be provided by the sysconf() function. + + // AIO_LISTIO_MAX :: sysconf(._AIO_LISTIO_MAX) + // AIO_MAX :: sysconf(._AIO_MAX) + // AIO_PRIO_DELTA_MAX :: sysconf(._AIO_PRIO_DELTA_MAX) + ARG_MAX :: 1024 * 1024 + // ATEXIT_MAX :: sysconf(._ATEXIT_MAX) + CHILD_MAX :: 266 + // DELAYTIMER_MAX :: sysconf(._DELAYTIMER_MAX) + // HOST_NAME_MAX :: sysconf(._HOST_NAME_MAX) + IOV_MAX :: 1024 + // LOGIN_NAME_MAX :: sysconf(._LOGIN_NAME_MAX) + // MQ_OPEN_MAX :: sysconf(._MQ_OPEN_MAX) + // MQ_PRIO_MAX :: sysconf(._MQ_PRIO_MAX) + PAGESIZE :: PAGE_SIZE + PAGE_SIZE :: 1 << 12 + PTHREAD_DESTRUCTOR_ITERATIONS :: 4 + PTHREAD_KEYS_MAX :: 512 + PTHREAD_STACK_MIN :: 16384 when ODIN_ARCH == .arm64 else 8192 + // RTSIG_MAX :: sysconf(._RTSIG_MAX) + // SEM_NSEMS_MAX :: sysconf(._SEM_NSEMS_MAX) + // SEM_VALUE_MAX :: sysconf(._SEM_VALUE_MAX) + // SIGQUEUE_MAX :: sysconf(._SIGQUEUE_MAX) + // SS_REPL_MAX :: sysconf(._SS_REPL_MAX) + // STREAM_MAX :: sysconf(._STREAM_MAX) + // SYMLOOP_MAX :: sysconf(._SYMLOOP_MAX) + // TIMER_MAX :: sysconf(._TIMER_MAX) + // TRACE_EVENT_NAME_MAX :: sysconf(._TRACE_EVENT_NAME_MAX) + // TRACE_NAME_MAX :: sysconf(._TRACE_NAME_MAX) + // TRACE_SYS_MAX :: sysconf(._TRACE_SYS_MAX) + // TRACE_USER_EVENT_MAX :: sysconf(._TRACE_USER_EVENT_MAX) + // TTY_NAME_MAX :: sysconf(._TTY_NAME_MAX) + // TZNAME_MAX :: sysconf(._TZNAME_MAX) + + // The values in the following list may be constants within an implementation or may vary from + // one pathname to another. + // For example, file systems or directories may have different characteristics. + // + // A definition of one of the symbolic constants in the following list shall be omitted from the + // header on specific implementations where the corresponding value is equal to or + // greater than the stated minimum, but where the value can vary depending on the file to which + // it is applied. + // The actual value supported for a specific pathname shall be provided by the pathconf() function. + + // FILESIZEBITS :: pathconf(".", ._FILESIZEBITS) + LINK_MAX :: 32767 + MAX_CANON :: 1024 + MAX_INPUT :: 1024 + NAME_MAX :: 255 + PATH_MAX :: 1024 + PIPE_BUF :: 512 + // POSIX_ALLOC_SIZE_MIN :: pathconf("foo.txt", ._POSIX_ALLOC_SIZE_MIN) + // POSIX_REC_INCR_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_INCR_XFER_SIZE) + // POSIX_REC_MAX_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MAX_XFER_SIZE) + // POSIX_REC_MIN_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MIN_XFER_SIZE) + // POSIX_REC_XFER_ALIGN :: pathconf("foo.txt", ._POSIX_REC_XFER_ALIGN) + // SYMLINK_MAX :: pathconf(".", ._SYMLINK_MAX) + + + // The magnitude limitations in the following list shall be fixed by specific implementations. + // An application should assume that the value of the symbolic constant defined by + // in a specific implementation is the minimum that pertains whenever the application is run + // under that implementation. + // A specific instance of a specific implementation may increase the value relative to that + // supplied by for that implementation. + // The actual value supported by a specific instance shall be provided by the sysconf() function. + + BC_BASE_MAX :: 99 + BC_DIM_MAX :: 2048 + BC_SCALE_MAX :: 99 + BC_STRING_MAX :: 1000 + CHARCLASS_NAME_MAX :: 14 + COLL_WEIGHTS_MAX :: 2 + EXPR_NEST_MAX :: 2 + LINE_MAX :: 2048 + NGROUPS_MAX :: 16 + RE_DUP_MAX :: 255 + + // Other limits. + + NL_ARGMAX :: 9 + NL_LANGMAX :: 14 + NL_MSGMAX :: 32767 + NL_SETMAX :: 255 + NL_TEXTMAX :: 2048 + NZERO :: 20 + +} else when ODIN_OS == .FreeBSD { + // A definition of one of the symbolic constants in the following list shall be omitted from + // on specific implementations where the corresponding value is equal to or greater + // than the stated minimum, but is unspecified. + // + // This indetermination might depend on the amount of available memory space on a specific + // instance of a specific implementation. The actual value supported by a specific instance shall + // be provided by the sysconf() function. + + // AIO_LISTIO_MAX :: sysconf(._AIO_LISTIO_MAX) + // AIO_MAX :: sysconf(._AIO_MAX) + // AIO_PRIO_DELTA_MAX :: sysconf(._AIO_PRIO_DELTA_MAX) + ARG_MAX :: 2 * 256 * 1024 + // ATEXIT_MAX :: sysconf(._ATEXIT_MAX) + CHILD_MAX :: 40 + // DELAYTIMER_MAX :: sysconf(._DELAYTIMER_MAX) + // HOST_NAME_MAX :: sysconf(._HOST_NAME_MAX) + IOV_MAX :: 1024 + // LOGIN_NAME_MAX :: sysconf(._LOGIN_NAME_MAX) + // MQ_OPEN_MAX :: sysconf(._MQ_OPEN_MAX) + MQ_PRIO_MAX :: 64 + PAGESIZE :: PAGE_SIZE + PAGE_SIZE :: 1 << 12 + PTHREAD_DESTRUCTOR_ITERATIONS :: 4 + PTHREAD_KEYS_MAX :: 256 + PTHREAD_STACK_MIN :: MINSIGSTKSZ + // RTSIG_MAX :: sysconf(._RTSIG_MAX) + // SEM_NSEMS_MAX :: sysconf(._SEM_NSEMS_MAX) + // SEM_VALUE_MAX :: sysconf(._SEM_VALUE_MAX) + // SIGQUEUE_MAX :: sysconf(._SIGQUEUE_MAX) + // SS_REPL_MAX :: sysconf(._SS_REPL_MAX) + // STREAM_MAX :: sysconf(._STREAM_MAX) + // SYMLOOP_MAX :: sysconf(._SYMLOOP_MAX) + // TIMER_MAX :: sysconf(._TIMER_MAX) + // TRACE_EVENT_NAME_MAX :: sysconf(._TRACE_EVENT_NAME_MAX) + // TRACE_NAME_MAX :: sysconf(._TRACE_NAME_MAX) + // TRACE_SYS_MAX :: sysconf(._TRACE_SYS_MAX) + // TRACE_USER_EVENT_MAX :: sysconf(._TRACE_USER_EVENT_MAX) + // TTY_NAME_MAX :: sysconf(._TTY_NAME_MAX) + // TZNAME_MAX :: sysconf(._TZNAME_MAX) + + // The values in the following list may be constants within an implementation or may vary from + // one pathname to another. + // For example, file systems or directories may have different characteristics. + // + // A definition of one of the symbolic constants in the following list shall be omitted from the + // header on specific implementations where the corresponding value is equal to or + // greater than the stated minimum, but where the value can vary depending on the file to which + // it is applied. + // The actual value supported for a specific pathname shall be provided by the pathconf() function. + + // FILESIZEBITS :: pathconf(".", ._FILESIZEBITS) + // LINK_MAX :: pathconf(foo.txt", ._LINK_MAX) + MAX_CANON :: 255 + MAX_INPUT :: 255 + NAME_MAX :: 255 + PATH_MAX :: 1024 + PIPE_BUF :: 512 + // POSIX_ALLOC_SIZE_MIN :: pathconf("foo.txt", ._POSIX_ALLOC_SIZE_MIN) + // POSIX_REC_INCR_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_INCR_XFER_SIZE) + // POSIX_REC_MAX_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MAX_XFER_SIZE) + // POSIX_REC_MIN_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MIN_XFER_SIZE) + // POSIX_REC_XFER_ALIGN :: pathconf("foo.txt", ._POSIX_REC_XFER_ALIGN) + // SYMLINK_MAX :: pathconf(".", ._SYMLINK_MAX) + + + // The magnitude limitations in the following list shall be fixed by specific implementations. + // An application should assume that the value of the symbolic constant defined by + // in a specific implementation is the minimum that pertains whenever the application is run + // under that implementation. + // A specific instance of a specific implementation may increase the value relative to that + // supplied by for that implementation. + // The actual value supported by a specific instance shall be provided by the sysconf() function. + + BC_BASE_MAX :: 99 + BC_DIM_MAX :: 2048 + BC_SCALE_MAX :: 99 + BC_STRING_MAX :: 1000 + CHARCLASS_NAME_MAX :: 14 + COLL_WEIGHTS_MAX :: 10 + EXPR_NEST_MAX :: 32 + LINE_MAX :: 2048 + NGROUPS_MAX :: 1023 + RE_DUP_MAX :: 255 + + // Other limits. + + NL_ARGMAX :: 4096 + NL_LANGMAX :: 31 + NL_MSGMAX :: 32767 + NL_SETMAX :: 255 + NL_TEXTMAX :: 2048 + NZERO :: 0 + +} else when ODIN_OS == .NetBSD { + + // A definition of one of the symbolic constants in the following list shall be omitted from + // on specific implementations where the corresponding value is equal to or greater + // than the stated minimum, but is unspecified. + // + // This indetermination might depend on the amount of available memory space on a specific + // instance of a specific implementation. The actual value supported by a specific instance shall + // be provided by the sysconf() function. + + // AIO_LISTIO_MAX :: sysconf(._AIO_LISTIO_MAX) + // AIO_MAX :: sysconf(._AIO_MAX) + // AIO_PRIO_DELTA_MAX :: sysconf(._AIO_PRIO_DELTA_MAX) + ARG_MAX :: 256 * 1024 + // ATEXIT_MAX :: sysconf(._ATEXIT_MAX) + CHILD_MAX :: 160 + // DELAYTIMER_MAX :: sysconf(._DELAYTIMER_MAX) + // HOST_NAME_MAX :: sysconf(._HOST_NAME_MAX) + IOV_MAX :: 1024 + LOGIN_NAME_MAX :: 17 + MQ_OPEN_MAX :: 512 + MQ_PRIO_MAX :: 32 + PAGESIZE :: PAGE_SIZE + PAGE_SIZE :: 1 << 12 + PTHREAD_DESTRUCTOR_ITERATIONS :: 4 + PTHREAD_KEYS_MAX :: 256 + // PTHREAD_STACK_MIN :: sysconf(._THREAD_STACK_MIN) + // RTSIG_MAX :: sysconf(._RTSIG_MAX) + // SEM_NSEMS_MAX :: sysconf(._SEM_NSEMS_MAX) + // SEM_VALUE_MAX :: sysconf(._SEM_VALUE_MAX) + // SIGQUEUE_MAX :: sysconf(._SIGQUEUE_MAX) + // SS_REPL_MAX :: sysconf(._SS_REPL_MAX) + // STREAM_MAX :: sysconf(._STREAM_MAX) + // SYMLOOP_MAX :: sysconf(._SYMLOOP_MAX) + // TIMER_MAX :: sysconf(._TIMER_MAX) + // TRACE_EVENT_NAME_MAX :: sysconf(._TRACE_EVENT_NAME_MAX) + // TRACE_NAME_MAX :: sysconf(._TRACE_NAME_MAX) + // TRACE_SYS_MAX :: sysconf(._TRACE_SYS_MAX) + // TRACE_USER_EVENT_MAX :: sysconf(._TRACE_USER_EVENT_MAX) + // TTY_NAME_MAX :: sysconf(._TTY_NAME_MAX) + // TZNAME_MAX :: sysconf(._TZNAME_MAX) + + // The values in the following list may be constants within an implementation or may vary from + // one pathname to another. + // For example, file systems or directories may have different characteristics. + // + // A definition of one of the symbolic constants in the following list shall be omitted from the + // header on specific implementations where the corresponding value is equal to or + // greater than the stated minimum, but where the value can vary depending on the file to which + // it is applied. + // The actual value supported for a specific pathname shall be provided by the pathconf() function. + + // FILESIZEBITS :: pathconf(".", ._FILESIZEBITS) + LINK_MAX :: 32767 + MAX_CANON :: 255 + MAX_INPUT :: 255 + NAME_MAX :: 511 + PATH_MAX :: 1024 + PIPE_BUF :: 512 + // POSIX_ALLOC_SIZE_MIN :: pathconf("foo.txt", ._POSIX_ALLOC_SIZE_MIN) + // POSIX_REC_INCR_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_INCR_XFER_SIZE) + // POSIX_REC_MAX_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MAX_XFER_SIZE) + // POSIX_REC_MIN_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MIN_XFER_SIZE) + // POSIX_REC_XFER_ALIGN :: pathconf("foo.txt", ._POSIX_REC_XFER_ALIGN) + // SYMLINK_MAX :: pathconf(".", ._SYMLINK_MAX) + + + // The magnitude limitations in the following list shall be fixed by specific implementations. + // An application should assume that the value of the symbolic constant defined by + // in a specific implementation is the minimum that pertains whenever the application is run + // under that implementation. + // A specific instance of a specific implementation may increase the value relative to that + // supplied by for that implementation. + // The actual value supported by a specific instance shall be provided by the sysconf() function. + + BC_BASE_MAX :: max(i32) + BC_DIM_MAX :: 65535 + BC_SCALE_MAX :: max(i32) + BC_STRING_MAX :: max(i32) + CHARCLASS_NAME_MAX :: 14 + COLL_WEIGHTS_MAX :: 2 + EXPR_NEST_MAX :: 32 + LINE_MAX :: 2048 + NGROUPS_MAX :: 16 + RE_DUP_MAX :: 255 + + // Other limits. + + NL_ARGMAX :: 9 + NL_LANGMAX :: 14 + NL_MSGMAX :: 32767 + NL_SETMAX :: 255 + NL_TEXTMAX :: 2048 + NZERO :: 20 + +} else when ODIN_OS == .OpenBSD { + + // A definition of one of the symbolic constants in the following list shall be omitted from + // on specific implementations where the corresponding value is equal to or greater + // than the stated minimum, but is unspecified. + // + // This indetermination might depend on the amount of available memory space on a specific + // instance of a specific implementation. The actual value supported by a specific instance shall + // be provided by the sysconf() function. + + // AIO_LISTIO_MAX :: sysconf(._AIO_LISTIO_MAX) + // AIO_MAX :: sysconf(._AIO_MAX) + // AIO_PRIO_DELTA_MAX :: sysconf(._AIO_PRIO_DELTA_MAX) + ARG_MAX :: 512 * 1024 + // ATEXIT_MAX :: sysconf(._ATEXIT_MAX) + CHILD_MAX :: 80 + // DELAYTIMER_MAX :: sysconf(._DELAYTIMER_MAX) + // HOST_NAME_MAX :: sysconf(._HOST_NAME_MAX) + IOV_MAX :: 1024 + LOGIN_NAME_MAX :: 32 + MQ_OPEN_MAX :: 512 + MQ_PRIO_MAX :: 32 + PAGESIZE :: PAGE_SIZE + PAGE_SIZE :: 1 << 12 + PTHREAD_DESTRUCTOR_ITERATIONS :: 4 + PTHREAD_KEYS_MAX :: 256 + PTHREAD_STACK_MIN :: 1 << 12 + // RTSIG_MAX :: sysconf(._RTSIG_MAX) + // SEM_NSEMS_MAX :: sysconf(._SEM_NSEMS_MAX) + SEM_VALUE_MAX :: max(u32) + // SIGQUEUE_MAX :: sysconf(._SIGQUEUE_MAX) + // SS_REPL_MAX :: sysconf(._SS_REPL_MAX) + // STREAM_MAX :: sysconf(._STREAM_MAX) + SYMLOOP_MAX :: 32 + // TIMER_MAX :: sysconf(._TIMER_MAX) + // TRACE_EVENT_NAME_MAX :: sysconf(._TRACE_EVENT_NAME_MAX) + // TRACE_NAME_MAX :: sysconf(._TRACE_NAME_MAX) + // TRACE_SYS_MAX :: sysconf(._TRACE_SYS_MAX) + // TRACE_USER_EVENT_MAX :: sysconf(._TRACE_USER_EVENT_MAX) + // TTY_NAME_MAX :: sysconf(._TTY_NAME_MAX) + // TZNAME_MAX :: sysconf(._TZNAME_MAX) + + // The values in the following list may be constants within an implementation or may vary from + // one pathname to another. + // For example, file systems or directories may have different characteristics. + // + // A definition of one of the symbolic constants in the following list shall be omitted from the + // header on specific implementations where the corresponding value is equal to or + // greater than the stated minimum, but where the value can vary depending on the file to which + // it is applied. + // The actual value supported for a specific pathname shall be provided by the pathconf() function. + + // FILESIZEBITS :: pathconf(".", ._FILESIZEBITS) + LINK_MAX :: 32767 + MAX_CANON :: 255 + MAX_INPUT :: 255 + NAME_MAX :: 255 + PATH_MAX :: 1024 + PIPE_BUF :: 512 + // POSIX_ALLOC_SIZE_MIN :: pathconf("foo.txt", ._POSIX_ALLOC_SIZE_MIN) + // POSIX_REC_INCR_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_INCR_XFER_SIZE) + // POSIX_REC_MAX_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MAX_XFER_SIZE) + // POSIX_REC_MIN_XFER_SIZE :: pathconf("foo.txt", ._POSIX_REC_MIN_XFER_SIZE) + // POSIX_REC_XFER_ALIGN :: pathconf("foo.txt", ._POSIX_REC_XFER_ALIGN) + SYMLINK_MAX :: PATH_MAX + + + // The magnitude limitations in the following list shall be fixed by specific implementations. + // An application should assume that the value of the symbolic constant defined by + // in a specific implementation is the minimum that pertains whenever the application is run + // under that implementation. + // A specific instance of a specific implementation may increase the value relative to that + // supplied by for that implementation. + // The actual value supported by a specific instance shall be provided by the sysconf() function. + + BC_BASE_MAX :: max(i32) + BC_DIM_MAX :: 65535 + BC_SCALE_MAX :: max(i32) + BC_STRING_MAX :: max(i32) + CHARCLASS_NAME_MAX :: 14 + COLL_WEIGHTS_MAX :: 2 + EXPR_NEST_MAX :: 32 + LINE_MAX :: 2048 + NGROUPS_MAX :: 16 + RE_DUP_MAX :: 255 + + // Other limits. + + NL_ARGMAX :: 9 + NL_LANGMAX :: 14 + NL_MSGMAX :: 32767 + NL_SETMAX :: 255 + NL_TEXTMAX :: 255 + NZERO :: 20 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/locale.odin b/core/sys/posix/locale.odin new file mode 100644 index 000000000..1f2a336b5 --- /dev/null +++ b/core/sys/posix/locale.odin @@ -0,0 +1,93 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// locale.h - category macros + +foreign lib { + /* + Sets the components of an object with the type lconv with the values appropriate for the + formatting of numeric quantities (monetary and otherwise) according to the rules of the current + locale. + + Returns: a pointer to the lconv structure, might be invalidated by subsequent calls to localeconv() and setlocale() + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/localeconv.html ]] + */ + localeconv :: proc() -> ^lconv --- + + /* + Selects the appropriate piece of the global locale, as specified by the category and locale arguments, + and can be used to change or query the entire global locale or portions thereof. + + Returns: the current locale if `locale` is `nil`, the set locale otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setlocale.html ]] + */ + @(link_name=LSETLOCALE) + setlocale :: proc(category: Locale_Category, locale: cstring) -> cstring --- +} + +Locale_Category :: enum c.int { + ALL = LC_ALL, + COLLATE = LC_COLLATE, + CTYPE = LC_CTYPE, + MESSAGES = LC_MESSAGES, + MONETARY = LC_MONETARY, + NUMERIC = LC_NUMERIC, + TIME = LC_TIME, +} + +when ODIN_OS == .NetBSD { + @(private) LSETLOCALE :: "__setlocale50" +} else { + @(private) LSETLOCALE :: "setlocale" +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + // NOTE: All of these fields are standard ([PSX]). + lconv :: struct { + decimal_point: cstring, + thousand_sep: cstring, + grouping: cstring, + int_curr_symbol: cstring, + currency_symbol: cstring, + mon_decimal_points: cstring, + mon_thousands_sep: cstring, + mon_grouping: cstring, + positive_sign: cstring, + negative_sign: cstring, + int_frac_digits: c.char, + frac_digits: c.char, + p_cs_precedes: c.char, + p_sep_by_space: c.char, + n_cs_precedes: c.char, + n_sep_by_space: c.char, + p_sign_posn: c.char, + n_sign_posn: c.char, + int_p_cs_precedes: c.char, + int_n_cs_precedes: c.char, + int_p_sep_by_space: c.char, + int_n_sep_by_space: c.char, + int_p_sign_posn: c.char, + int_n_sign_posn: c.char, + } + + LC_ALL :: 0 + LC_COLLATE :: 1 + LC_CTYPE :: 2 + LC_MESSAGES :: 6 + LC_MONETARY :: 3 + LC_NUMERIC :: 4 + LC_TIME :: 5 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/monetary.odin b/core/sys/posix/monetary.odin new file mode 100644 index 000000000..b4f0c31ee --- /dev/null +++ b/core/sys/posix/monetary.odin @@ -0,0 +1,42 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// monetary.h - monetary types + +foreign lib { + + /* + Places characters into the array pointed to by s as controlled by the string format. + No more than maxsize bytes are placed into the array. + + Returns: -1 (setting errno) on failure, the number of bytes added to s otherwise + + Example: + posix.setlocale(.ALL, "en_US.UTF-8") + value := 123456.789 + buffer: [100]byte + size := posix.strfmon(raw_data(buffer[:]), len(buffer), "%n", value) + if int(size) == -1 { + fmt.panicf("strfmon failure: %s", posix.strerror(posix.errno())) + } + fmt.println(string(buffer[:size])) + + Output: + $123,456.79 + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strfmon.html ]] + */ + strfmon :: proc( + s: [^]byte, + maxsize: c.size_t, + format: cstring, + #c_vararg args: ..any, + ) -> c.size_t --- +} diff --git a/core/sys/posix/net_if.odin b/core/sys/posix/net_if.odin new file mode 100644 index 000000000..aaeb5088a --- /dev/null +++ b/core/sys/posix/net_if.odin @@ -0,0 +1,60 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// net/if.h - sockets local interfaces + +foreign lib { + /* + Retrieve an array of name indexes. Where the last one has an index of 0 and name of nil. + + Returns: nil (setting errno) on failure, an array that should be freed with if_freenameindex otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/if_nameindex.html ]] + */ + if_nameindex :: proc() -> [^]if_nameindex_t --- + + /* + Returns the interface index matching the name or zero. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/if_nametoindex.html ]] + */ + if_nametoindex :: proc(name: cstring) -> c.uint --- + + /* + Returns the name corresponding to the index. + + ifname should be at least IF_NAMESIZE bytes in size. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/if_indextoname.html ]] + */ + if_indextoname :: proc(ifindex: c.uint, ifname: [^]byte) -> cstring --- + + /* + Frees memory allocated by if_nameindex. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/if_freenameindex.html ]] + */ + if_freenameindex :: proc(ptr: ^if_nameindex_t) --- +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + // NOTE: `_t` suffix added due to name conflict. + + if_nameindex_t :: struct { + if_index: c.uint, /* [PSX] 1, 2, ... */ + if_name: cstring, /* [PSX] null terminated name: "le0", ... */ + } + + IF_NAMESIZE :: 16 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/netdb.odin b/core/sys/posix/netdb.odin new file mode 100644 index 000000000..7570f9a22 --- /dev/null +++ b/core/sys/posix/netdb.odin @@ -0,0 +1,443 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// netdb.h - definitions for network database operations + +foreign lib { + /* + Translate node/serv name and return a set of socket addresses and associated information to be + used in creating a socket with which to address the specified service. + + Example: + // The following (incomplete) program demonstrates the use of getaddrinfo() to obtain the + // socket address structure(s) for the service named in the program's command-line argument. + // The program then loops through each of the address structures attempting to create and bind + // a socket to the address, until it performs a successful bind(). + + args := runtime.args__ + if len(args) != 2 { + fmt.eprintfln("Usage: %s port", args[0]) + posix.exit(1) + } + + hints: posix.addrinfo + hints.ai_socktype = .DGRAM + hints.ai_flags = { .PASSIVE } + + result: ^posix.addrinfo + s := posix.getaddrinfo(nil, args[1], &hints, &result) + if s != .NONE { + fmt.eprintfln("getaddrinfo: %s", posix.gai_strerror(s)) + posix.exit(1) + } + defer posix.freeaddrinfo(result) + + // Try each address until a successful bind(). + rp: ^posix.addrinfo + for rp = result; rp != nil; rp = rp.ai_next { + sfd := posix.socket(rp.ai_family, rp.ai_socktype, rp.ai_protocol) + if sfd == -1 { + continue + } + + if posix.bind(sfd, rp.ai_addr, rp.ai_addrlen) == 0 { + // Success. + break + } + + posix.close(sfd) + } + + if rp == nil { + fmt.eprintln("Could not bind") + posix.exit(1) + } + + // Use the socket... + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html ]] + */ + getaddrinfo :: proc( + nodename: cstring, + servname: cstring, + hints: ^addrinfo, + res: ^^addrinfo, + ) -> Info_Errno --- + + /* + Frees the given address info linked list. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html ]] + */ + freeaddrinfo :: proc(ai: ^addrinfo) --- + + /* + Translate a socket address to a node name and service location. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getnameinfo.html ]] + */ + getnameinfo :: proc( + sa: ^sockaddr, salen: socklen_t, + node: [^]byte, nodelen: socklen_t, + service: [^]byte, servicelen: socklen_t, + flags: Nameinfo_Flags, + ) -> Info_Errno --- + + /* + Get a textual description for the address info errors. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gai_strerror.html ]] + */ + gai_strerror :: proc(ecode: Info_Errno) -> cstring --- + + /* + Opens a connection to the database and set the next entry to the first entry in the database. + + This reads /etc/hosts on most systems. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sethostent.html ]] + */ + sethostent :: proc(stayopen: b32) --- + + /* + Reads the next entry in the database, opening and closing a connection as necessary. + + This reads /etc/hosts on most systems. + + Example: + posix.sethostent(true) + defer posix.endhostent() + for ent := posix.gethostent(); ent != nil; ent = posix.gethostent() { + fmt.println(ent) + fmt.println(ent.h_addr_list[0][:ent.h_length]) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sethostent.html ]] + */ + gethostent :: proc() -> ^hostent --- + + /* + Closes the connection to the database. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sethostent.html ]] + */ + endhostent :: proc() --- + + /* + Opens and rewinds the database. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setnetent.html ]] + */ + setnetent :: proc(stayopen: b32) --- + + /* + Reads the next entry of the database. + + Example: + posix.setnetent(true) + defer posix.endnetent() + for ent := posix.getnetent(); ent != nil; ent = posix.getnetent() { + fmt.println(ent) + fmt.println(transmute([4]byte)ent.n_net) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setnetent.html ]] + */ + getnetent :: proc() -> ^netent --- + + /* + Search the database from the beginning, and find the first entry that matches. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setnetent.html ]] + */ + getnetbyaddr :: proc(net: c.uint32_t, type: AF) -> ^netent --- + + /* + Search the database from the beginning, and find the first entry that matches. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setnetent.html ]] + */ + getnetbyname :: proc(name: cstring) -> ^netent --- + + /* + Closes the database. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setnetent.html ]] + */ + endnetent :: proc() --- + + /* + Opens and rewinds the database. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setprotoent.html ]] + */ + setprotoent :: proc(stayopen: b32) --- + + /* + Reads the next entry of the database. + + Example: + posix.setprotoent(true) + defer posix.endprotoent() + for ent := posix.getprotoent(); ent != nil; ent = posix.getprotoent() { + fmt.println(ent) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setprotoent.html ]] + */ + getprotoent :: proc() -> ^protoent --- + + /* + Search the database from the beginning, and find the first entry that matches. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setprotoent.html ]] + */ + getprotobyname :: proc(name: cstring) -> ^protoent --- + + /* + Search the database from the beginning, and find the first entry that matches. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setprotoent.html ]] + */ + getprotobynumber :: proc(proto: c.int) -> ^protoent --- + + /* + Closes the database. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setprotoent.html ]] + */ + endprotoent :: proc() --- + + /* + Opens and rewinds the database. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setservent.html ]] + */ + setservent :: proc(stayopen: b32) --- + + /* + Reads the next entry of the database. + + Example: + posix.setservent(true) + defer posix.endservent() + for ent := posix.getservent(); ent != nil; ent = posix.getservent() { + fmt.println(ent) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setservent.html ]] + */ + getservent :: proc() -> ^servent --- + + /* + Search the database from the beginning, and find the first entry that matches. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setservent.html ]] + */ + getservbyname :: proc(name: cstring, proto: cstring) -> ^servent --- + + /* + Search the database from the beginning, and find the first entry that matches. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setservent.html ]] + */ + getservbyport :: proc(port: c.int, proto: cstring) -> ^servent --- + + /* + Closes the database. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setservent.html ]] + */ + endservent :: proc() --- +} + +Addrinfo_Flag_Bits :: enum c.int { + // Socket address is intended for bind(). + PASSIVE = log2(AI_PASSIVE), + // Request for canonical name. + CANONNAME = log2(AI_CANONNAME), + // Return numeric host address as name. + NUMERICHOST = log2(AI_NUMERICHOST), + // Inhibit service name resolution. + NUMERICSERV = log2(AI_NUMERICSERV), + // If no IPv6 addresses are found, query for IPv4 addresses and return them to the + // caller as IPv4-mapped IPv6 addresses. + V4MAPPED = log2(AI_V4MAPPED), + // Query for both IPv4 and IPv6 addresses. + ALL = log2(AI_ALL), + // Query for IPv4 addresses only when an IPv4 address is configured; query for IPv6 addresses + // only when an IPv6 address is configured. + ADDRCONFIG = log2(AI_ADDRCONFIG), +} +Addrinfo_Flags :: bit_set[Addrinfo_Flag_Bits; c.int] + +Nameinfo_Flag_Bits :: enum c.int { + // Only the nodename portion of the FQDN is returned for local hosts. + NOFQDN = log2(NI_NOFQDN), + // The numeric form of the node's address is returned instead of its name. + NUMERICHOST = log2(NI_NUMERICHOST), + // Return an error if the node's name cannot be located in the database. + NAMEREQD = log2(NI_NAMEREQD), + // The numeric form of the service address is returned instead of its name. + NUMERICSERV = log2(NI_NUMERICSERV), + // For IPv6 addresses, the numeric form of the scope identifier is returned instead of its name. + NUMERICSCOPE = log2(NI_NUMERICSCOPE), + // Indicates that the service is a datagram service (SOCK_DGRAM). + DGRAM = log2(NI_DGRAM), +} +Nameinfo_Flags :: bit_set[Nameinfo_Flag_Bits; c.int] + +Info_Errno :: enum c.int { + NONE = 0, + // The name could not be resolved at this time. Future attempts may succeed. + AGAIN = EAI_AGAIN, + // The flags had an invalid value. + BADFLAGS = EAI_BADFLAGS, + // A non-recoverable error ocurred. + FAIL = EAI_FAIL, + // The address family was not recognized or the address length was invald for the specified family. + FAMILY = EAI_FAMILY, + // There was a memory allocation failure. + MEMORY = EAI_MEMORY, + // The name does not resolve for the supplied parameters. + NONAME = EAI_NONAME, + // The service passed was not recognized for the specified socket. + SERVICE = EAI_SERVICE, + // The intended socket type was not recognized. + SOCKTYPE = EAI_SOCKTYPE, + // A system error occurred. The error code can be found in errno. + SYSTEM = EAI_SYSTEM, + // An argument buffer overflowed. + OVERFLOW = EAI_OVERFLOW, +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + hostent :: struct { + h_name: cstring, /* [PSX] official name of host */ + h_aliases: [^]cstring `fmt:"v,0"`, /* [PSX] alias list */ + h_addrtype: AF, /* [PSX] host address type */ + h_length: c.int, /* [PSX] length of address */ + h_addr_list: [^][^]byte `fmt:"v,0"`, /* [PSX] list of addresses from name server */ + } + + netent :: struct { + n_name: cstring, /* [PSX] official name of net */ + n_aliases: [^]cstring `fmt:"v,0"`, /* [PSX] alias list */ + n_addrtype: AF, /* [PSX] net address type */ + n_net: c.uint32_t, /* [PSX] network # */ + } + + protoent :: struct { + p_name: cstring, /* [PSX] official protocol name */ + p_aliases: [^]cstring `fmt:"v,0"`, /* [PSX] alias list */ + p_proto: c.int, /* [PSX] protocol # */ + } + + servent :: struct { + s_name: cstring, /* [PSX] official service name */ + s_aliases: [^]cstring `fmt:"v,0"`, /* [PSX] alias list */ + s_port: c.int, /* [PSX] port # */ + s_proto: cstring, /* [PSX] protocol # */ + } + + // The highest reserved port number. + IPPORT_RESERVED :: 1024 + + addrinfo :: struct { + ai_flags: Addrinfo_Flags, /* [PSX] input flags */ + ai_family: AF, /* [PSX] address family of socket */ + ai_socktype: Sock, /* [PSX] socket type */ + ai_protocol: Protocol, /* [PSX] protocol of socket */ + ai_addrlen: socklen_t, /* [PSX] length of socket address */ + ai_canonname: cstring, /* [PSX] canonical name of service location */ + ai_addr: ^sockaddr, /* [PSX] binary address */ + ai_next: ^addrinfo, /* [PSX] pointer to next in list */ + } + + when ODIN_OS == .Darwin { + + AI_PASSIVE :: 0x00000001 + AI_CANONNAME :: 0x00000002 + AI_NUMERICHOST :: 0x00000004 + AI_NUMERICSERV :: 0x00001000 + AI_V4MAPPED :: 0x00000800 + AI_ALL :: 0x00000100 + AI_ADDRCONFIG :: 0x00000400 + + NI_NOFQDN :: 0x00000001 + NI_NUMERICHOST :: 0x00000002 + NI_NAMEREQD :: 0x00000004 + NI_NUMERICSERV :: 0x00000008 + NI_NUMERICSCOPE :: 0x00000100 + NI_DGRAM :: 0x00000010 + + } else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD { + + AI_PASSIVE :: 0x00000001 + AI_CANONNAME :: 0x00000002 + AI_NUMERICHOST :: 0x00000004 + AI_NUMERICSERV :: 0x00000008 + AI_V4MAPPED :: 0x00000800 // NOTE: not implemented on netbsd + AI_ALL :: 0x00000100 // NOTE: not implemented on netbsd + AI_ADDRCONFIG :: 0x00000400 + + NI_NOFQDN :: 0x00000001 + NI_NUMERICHOST :: 0x00000002 + NI_NAMEREQD :: 0x00000004 + NI_NUMERICSERV :: 0x00000008 + NI_NUMERICSCOPE :: 0x00000010 + NI_DGRAM :: 0x00000020 + + } else when ODIN_OS == .OpenBSD { + + AI_PASSIVE :: 1 + AI_CANONNAME :: 2 + AI_NUMERICHOST :: 4 + AI_NUMERICSERV :: 16 + AI_V4MAPPED :: 0x00000800 // NOTE: not implemented + AI_ALL :: 0x00000100 // NOTE: not implemented + AI_ADDRCONFIG :: 64 + + NI_NOFQDN :: 4 + NI_NUMERICHOST :: 1 + NI_NAMEREQD :: 8 + NI_NUMERICSERV :: 2 + NI_NUMERICSCOPE :: 32 + NI_DGRAM :: 16 + } + + when ODIN_OS == .OpenBSD { + EAI_AGAIN :: -3 + EAI_BADFLAGS :: -1 + EAI_FAIL :: -4 + EAI_FAMILY :: -6 + EAI_MEMORY :: -10 + EAI_NONAME :: -2 + EAI_SERVICE :: -8 + EAI_SOCKTYPE :: -7 + EAI_SYSTEM :: -11 + EAI_OVERFLOW :: -14 + } else { + EAI_AGAIN :: 2 + EAI_BADFLAGS :: 3 + EAI_FAIL :: 4 + EAI_FAMILY :: 5 + EAI_MEMORY :: 6 + EAI_NONAME :: 8 + EAI_SERVICE :: 9 + EAI_SOCKTYPE :: 10 + EAI_SYSTEM :: 11 + EAI_OVERFLOW :: 14 + } + +}else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/netinet_in.odin b/core/sys/posix/netinet_in.odin new file mode 100644 index 000000000..3926c5288 --- /dev/null +++ b/core/sys/posix/netinet_in.odin @@ -0,0 +1,199 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// netinet/in.h - Internet address family + +foreign lib { + in6addr_any: in6_addr + in6addr_loopback: in6_addr +} + +in_port_t :: u16be +in_addr_t :: u32be + +INET_ADDRSTRLEN :: 16 +INET6_ADDRSTRLEN :: 46 + +Protocol :: enum c.int { + IP = IPPROTO_IP, + ICMP = IPPROTO_ICMP, + IPV6 = IPPROTO_IPV6, + RAW = IPPROTO_RAW, + TCP = IPPROTO_TCP, + UDP = IPPROTO_UDP, +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + in_addr :: struct { + s_addr: in_addr_t, /* [PSX] big endian address */ + } + + in6_addr :: struct { + using _: struct #raw_union { + s6_addr: [16]c.uint8_t, /* [PSX] big endian address */ + __u6_addr16: [8]c.uint16_t, + __u6_addr32: [4]c.uint32_t, + }, + } + + sockaddr_in :: struct { + sin_len: c.uint8_t, + sin_family: sa_family_t, /* [PSX] AF_INET (but a smaller size) */ + sin_port: in_port_t, /* [PSX] port number */ + sin_addr: in_addr, /* [PSX] IP address */ + sin_zero: [8]c.char, + } + + sockaddr_in6 :: struct { + sin6_len: c.uint8_t, + sin6_family: sa_family_t, /* [PSX] AF_INET6 (but a smaller size) */ + sin6_port: in_port_t, /* [PSX] port number */ + sin6_flowinfo: c.uint32_t, /* [PSX] IPv6 traffic class and flow information */ + sin6_addr: in6_addr, /* [PSX] IPv6 address */ + sin6_scope_id: c.uint32_t, /* [PSX] set of interfaces for a scope */ + } + + ipv6_mreq :: struct { + ipv6mr_multiaddr: in6_addr, /* [PSX] IPv6 multicast address */ + ipv6mr_interface: c.uint, /* [PSX] interface index */ + } + + IPPROTO_IP :: 0 + IPPROTO_ICMP :: 1 + IPPROTO_IPV6 :: 41 + IPPROTO_RAW :: 255 + IPPROTO_TCP :: 6 + IPPROTO_UDP :: 17 + + INADDR_ANY :: 0x00000000 + INADDR_BROADCAST :: 0xFFFFFFFF + + IPV6_JOIN_GROUP :: 12 + IPV6_LEAVE_GROUP :: 13 + IPV6_MULTICAST_HOPS :: 10 + IPV6_MULTICAST_IF :: 9 + IPV6_MULTICAST_LOOP :: 11 + IPV6_UNICAST_HOPS :: 4 + IPV6_V6ONLY :: 27 + + IN6_IS_ADDR_UNSPECIFIED :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + return a.s6_addr == 0 + } + + IN6_IS_ADDR_LOOPBACK :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + a := a + return ( + (^c.uint32_t)(&a.s6_addr[0])^ == 0 && + (^c.uint32_t)(&a.s6_addr[4])^ == 0 && + (^c.uint32_t)(&a.s6_addr[8])^ == 0 && + (^u32be)(&a.s6_addr[12])^ == 1 \ + ) + } + + IN6_IS_ADDR_MULTICAST :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + return a.s6_addr[0] == 0xff + } + + IN6_IS_ADDR_LINKLOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + return a.s6_addr[0] == 0xfe && a.s6_addr[1] & 0xc0 == 0x80 + } + + IN6_IS_ADDR_SITELOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + return a.s6_addr[0] == 0xfe && a.s6_addr[1] & 0xc0 == 0xc0 + } + + IN6_IS_ADDR_V4MAPPED :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + a := a + return ( + (^c.uint32_t)(&a.s6_addr[0])^ == 0 && + (^c.uint32_t)(&a.s6_addr[4])^ == 0 && + (^u32be)(&a.s6_addr[8])^ == 0x0000ffff \ + ) + } + + IN6_IS_ADDR_V4COMPAT :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + a := a + return ( + (^c.uint32_t)(&a.s6_addr[0])^ == 0 && + (^c.uint32_t)(&a.s6_addr[4])^ == 0 && + (^c.uint32_t)(&a.s6_addr[8])^ == 0 && + (^c.uint32_t)(&a.s6_addr[12])^ != 0 && + (^u32be)(&a.s6_addr[12])^ != 1 \ + ) + } + + @(private) + __IPV6_ADDR_SCOPE_NODELOCAL :: 0x01 + @(private) + __IPV6_ADDR_SCOPE_LINKLOCAL :: 0x02 + @(private) + __IPV6_ADDR_SCOPE_SITELOCAL :: 0x05 + @(private) + __IPV6_ADDR_SCOPE_ORGLOCAL :: 0x08 + @(private) + __IPV6_ADDR_SCOPE_GLOBAL :: 0x0e + + @(private) + IPV6_ADDR_MC_FLAGS :: #force_inline proc "contextless" (a: in6_addr) -> c.uint8_t { + return a.s6_addr[1] & 0xf0 + } + + @(private) + IPV6_ADDR_MC_FLAGS_TRANSIENT :: 0x10 + @(private) + IPV6_ADDR_MC_FLAGS_PREFIX :: 0x20 + @(private) + IPV6_ADDR_MC_FLAGS_UNICAST_BASED :: IPV6_ADDR_MC_FLAGS_TRANSIENT | IPV6_ADDR_MC_FLAGS_PREFIX + + @(private) + __IPV6_ADDR_MC_SCOPE :: #force_inline proc "contextless" (a: in6_addr) -> c.uint8_t { + return a.s6_addr[1] & 0x0f + } + + IN6_IS_ADDR_MC_NODELOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + return ( + IN6_IS_ADDR_MULTICAST(a) && + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_NODELOCAL) \ + ) + } + + IN6_IS_ADDR_MC_LINKLOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + return ( + IN6_IS_ADDR_MULTICAST(a) && + (IPV6_ADDR_MC_FLAGS(a) != IPV6_ADDR_MC_FLAGS_UNICAST_BASED) && + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_LINKLOCAL) \ + ) + } + + IN6_IS_ADDR_MC_SITELOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + return ( + IN6_IS_ADDR_MULTICAST(a) && + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_SITELOCAL) \ + ) + } + + IN6_IS_ADDR_MC_ORGLOCAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + return ( + IN6_IS_ADDR_MULTICAST(a) && + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_ORGLOCAL) \ + ) + } + + IN6_IS_ADDR_MC_GLOBAL :: #force_inline proc "contextless" (a: in6_addr) -> b32 { + return ( + IN6_IS_ADDR_MULTICAST(a) && + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_GLOBAL) \ + ) + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/netinet_tcp.odin b/core/sys/posix/netinet_tcp.odin new file mode 100644 index 000000000..ecd084b38 --- /dev/null +++ b/core/sys/posix/netinet_tcp.odin @@ -0,0 +1,11 @@ +package posix + +// netinet/tcp.h - definitions for the Internet Transmission Control Protocol (TCP) + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + TCP_NODELAY :: 0x01 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/poll.odin b/core/sys/posix/poll.odin new file mode 100644 index 000000000..3e825e009 --- /dev/null +++ b/core/sys/posix/poll.odin @@ -0,0 +1,78 @@ +package posix + +import "base:intrinsics" + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// poll.h - definitions for the poll() function + +foreign lib { + /* + For each pointer in fds, poll() shall examine the given descriptor for the events. + poll will identify on which descriptors writes or reads can be done. + + Returns: -1 (setting errno) on failure, 0 on timeout, the amount of fds that have been changed on success. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html ]] + */ + poll :: proc(fds: [^]pollfd, nfds: nfds_t, timeout: c.int) -> c.int --- +} + +nfds_t :: c.uint + +Poll_Event_Bits :: enum c.short { + // Data other than high-priority data may be read without blocking. + IN = log2(POLLIN), + // Normal data may be read without blocking. + RDNORM = log2(POLLRDNORM), + // Priority data may be read without blocking. + RDBAND = log2(POLLRDBAND), + // High priority data may be read without blocking. + PRI = log2(POLLPRI), + + // Normal data may be written without blocking. + OUT = log2(POLLOUT), + // Equivalent to POLLOUT. + WRNORM = log2(POLLWRNORM), + // Priority data may be written. + WRBAND = log2(POLLWRBAND), + + // An error has occurred (revents only). + ERR = log2(POLLERR), + // Device hsa been disconnected (revents only). + HUP = log2(POLLHUP), + // Invalid fd member (revents only). + NVAL = log2(POLLNVAL), +} +Poll_Event :: bit_set[Poll_Event_Bits; c.short] + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + pollfd :: struct { + fd: FD, /* [PSX] the following descriptor being polled */ + events: Poll_Event, /* [PSX] the input event flags */ + revents: Poll_Event, /* [PSX] the output event flags */ + } + + POLLIN :: 0x0001 + POLLRDNORM :: 0x0040 + POLLRDBAND :: 0x0080 + POLLPRI :: 0x0002 + POLLOUT :: 0x0004 + POLLWRNORM :: POLLOUT + POLLWRBAND :: 0x0100 + + POLLERR :: 0x0008 + POLLHUP :: 0x0010 + POLLNVAL :: 0x0020 + +} else { + #panic("posix is unimplemented for the current target") +} + diff --git a/core/sys/posix/posix.odin b/core/sys/posix/posix.odin new file mode 100644 index 000000000..eb0109a3e --- /dev/null +++ b/core/sys/posix/posix.odin @@ -0,0 +1,26 @@ +package posix + +import "base:intrinsics" + +import "core:c" + +result :: enum c.int { + // Use `errno` and `strerror` for more information. + FAIL = -1, + // Operation succeeded. + OK = 0, +} + +FD :: distinct c.int + +@(private) +log2 :: intrinsics.constant_log2 + +when ODIN_OS == .Darwin && ODIN_ARCH == .amd64 { + @(private) + INODE_SUFFIX :: "$INODE64" +} else { + @(private) + INODE_SUFFIX :: "" +} + diff --git a/core/sys/posix/pthread.odin b/core/sys/posix/pthread.odin new file mode 100644 index 000000000..e264f6f6c --- /dev/null +++ b/core/sys/posix/pthread.odin @@ -0,0 +1,518 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD { + foreign import lib "system:pthread" +} else { + foreign import lib "system:c" +} + +// pthread.h - threads + +// NOTE: mutexes, rwlock, condition variables, once and barriers are left out in favour of `core:sync`. + +foreign lib { + /* + Initializes a thread attributes object. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_init.html ]] + */ + pthread_attr_init :: proc(attr: ^pthread_attr_t) -> Errno --- + + /* + Destroys a thread attributes object. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_init.html ]] + */ + pthread_attr_destroy :: proc(attr: ^pthread_attr_t) -> Errno --- + + /* + The detachstate attribute controls whether the thread is created in a detached state. + If the thread is created detached, then use of the ID of the newly created thread is an error. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getdetachstate.html ]] + */ + pthread_attr_getdetachstate :: proc(attr: ^pthread_attr_t, detachstate: ^Detach_State) -> Errno --- + + /* + The detachstate attribute controls whether the thread is created in a detached state. + If the thread is created detached, then use of the ID of the newly created thread is an error. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getdetachstate.html ]] + */ + pthread_attr_setdetachstate :: proc(attr: ^pthread_attr_t, detachstate: Detach_State) -> Errno --- + + /* + The guardsize attribute controls the size of the guard area for the created thread's stack. + The guardsize attribute provides protection against overflow of the stack pointer. + If a thread's stack is created with guard protection, the implementation allocates extra memory + at the overflow end of the stack as a buffer against stack overflow of the stack pointer. + If an application overflows into this buffer an error shall result (possibly in a SIGSEGV signal being delivered to the thread). + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setguardsize.html ]] + */ + pthread_attr_getguardsize :: proc(attr: ^pthread_attr_t, guardsize: ^c.size_t) -> Errno --- + + /* + The guardsize attribute controls the size of the guard area for the created thread's stack. + The guardsize attribute provides protection against overflow of the stack pointer. + If a thread's stack is created with guard protection, the implementation allocates extra memory + at the overflow end of the stack as a buffer against stack overflow of the stack pointer. + If an application overflows into this buffer an error shall result (possibly in a SIGSEGV signal being delivered to the thread). + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setguardsize.html ]] + */ + pthread_attr_setguardsize :: proc(attr: ^pthread_attr_t, guardsize: c.size_t) -> Errno --- + + /* + When the attributes objects are used by pthread_create(), the inheritsched attribute determines + how the other scheduling attributes of the created thread shall be set. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setinheritsched.html ]] + */ + pthread_attr_getinheritsched :: proc(attr: ^pthread_attr_t, inheritsched: ^Inherit_Sched) -> Errno --- + + /* + When the attributes objects are used by pthread_create(), the inheritsched attribute determines + how the other scheduling attributes of the created thread shall be set. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setinheritsched.html ]] + */ + pthread_attr_setinheritsched :: proc(attr: ^pthread_attr_t, inheritsched: Inherit_Sched) -> Errno --- + + /* + Gets the scheduling param. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setschedparam.html ]] + */ + pthread_attr_getschedparam :: proc(attr: ^pthread_attr_t, param: ^sched_param) -> Errno --- + + /* + Sets the scheduling param. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setschedparam.html ]] + */ + pthread_attr_setschedparam :: proc(attr: ^pthread_attr_t, param: ^sched_param) -> Errno --- + + /* + Gets the scheduling poicy. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getschedpolicy.html ]] + */ + pthread_attr_getschedpolicy :: proc(attr: ^pthread_attr_t, policy: ^Sched_Policy) -> Errno --- + + /* + Sets the scheduling poicy. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getschedpolicy.html ]] + */ + pthread_attr_setschedpolicy :: proc(attr: ^pthread_attr_t, policy: Sched_Policy) -> Errno --- + + /* + Gets the contention scope. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getscope.html ]] + */ + pthread_attr_getscope :: proc(attr: ^pthread_attr_t, contentionscope: ^Thread_Scope) -> Errno --- + + /* + Sets the contention scope. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getscope.html ]] + */ + pthread_attr_setscope :: proc(attr: ^pthread_attr_t, contentionscope: ^Thread_Scope) -> Errno --- + + /* + Get the area of storage to be used for the created thread's stack. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getstack.html ]] + */ + pthread_attr_getstack :: proc(attr: ^pthread_attr_t, stackaddr: ^[^]byte, stacksize: ^c.size_t) -> Errno --- + + /* + Specify the area of storage to be used for the created thread's stack. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getstack.html ]] + */ + pthread_attr_setstack :: proc(attr: ^pthread_attr_t, stackaddr: [^]byte, stacksize: c.size_t) -> Errno --- + + /* + Gets the stack size. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getstacksize.html ]] + */ + pthread_attr_getstacksize :: proc(attr: ^pthread_attr_t, stacksize: ^c.size_t) -> Errno --- + + /* + Sets the stack size. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getstacksize.html ]] + */ + pthread_attr_setstacksize :: proc(attr: ^pthread_attr_t, stacksize: c.size_t) -> Errno --- + + /* + Register fork handlers to be called before and after fork(). + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_atfork.html ]] + */ + pthread_atfork :: proc(prepare: proc "c" (), parent: proc "c" (), child: proc "c" ()) -> Errno --- + + + /* + Cancel the execution of a thread. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cancel.html ]] + */ + pthread_cancel :: proc(thread: pthread_t) -> Errno --- + + /* + Creates a new thread with the given attributes. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html ]] + */ + pthread_create :: proc( + thread: ^pthread_t, + attr: ^pthread_attr_t, + start_routine: proc "c" (arg: rawptr) -> rawptr, + arg: rawptr, + ) -> Errno --- + + + /* + Indicate that storage for the thread can be reclaimed when the thread terminates. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_detach.html ]] + */ + pthread_detach :: proc(thread: pthread_t) -> Errno --- + + /* + Compare thread IDs. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_equal.html ]] + */ + pthread_equal :: proc(t1: pthread_t, t2: pthread_t) -> b32 --- + + /* + Terminates the calling thread and make the given value available to any successfull join calls. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit.html ]] + */ + pthread_exit :: proc(value_ptr: rawptr) -> ! --- + + /* + Gets the current concurrency hint. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getconcurrency.html ]] + */ + pthread_getconcurrency :: proc() -> c.int --- + + /* + Sets the current desired concurrency hint. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getconcurrency.html ]] + */ + pthread_setconcurrency :: proc(new_level: c.int) -> Errno --- + + /* + Access a thread CPU-time clock. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getcpuclockid.html ]] + */ + pthread_getcpuclockid :: proc(thread_id: pthread_t, clock_id: ^clockid_t) -> Errno --- + + /* + Gets the scheduling policy and parameters. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getschedparam.html ]] + */ + pthread_getschedparam :: proc(thread: pthread_t, policy: ^Sched_Policy, param: ^sched_param) -> Errno --- + + /* + Sets the scheduling policy and parameters. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getschedparam.html ]] + */ + pthread_setschedparam :: proc(thread: pthread_t, policy: Sched_Policy, param: ^sched_param) -> Errno --- + + /* + Creates a thread-specific data key visible to all threads in the process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_key_create.html ]] + */ + pthread_key_create :: proc(key: ^pthread_key_t, destructor: proc "c" (value: rawptr) = nil) -> Errno --- + + /* + Deletes a thread-specific data key visible to all threads in the process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_key_delete.html ]] + */ + pthread_key_delete :: proc(key: pthread_key_t) -> Errno --- + + /* + Returns the value currently bound to the specified key on behalf of the calling thread. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getspecific.html ]] + */ + pthread_getspecific :: proc(key: pthread_key_t) -> rawptr --- + + /* + Sets the value currently bound to the specified key on behalf of the calling thread. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getspecific.html ]] + */ + pthread_setspecific :: proc(key: pthread_key_t, value: rawptr) -> Errno --- + + /* + Suspends execution of the calling thread until the target thread terminates. + + Example: + ar: [10_000]i32 + + sb1 := ar[:5_000] + sb2 := ar[5_000:] + + th1, th2: posix.pthread_t + + posix.pthread_create(&th1, nil, incer, &sb1) + posix.pthread_create(&th2, nil, incer, &sb2) + + posix.pthread_join(th1) + posix.pthread_join(th2) + + incer :: proc "c" (arg: rawptr) -> rawptr { + sb := (^[]i32)(arg) + for &val in sb { + val += 1 + } + + return nil + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_join.html ]] + */ + pthread_join :: proc(thread: pthread_t, value_ptr: ^rawptr = nil) -> Errno --- + + /* + Get the calling thread ID. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html ]] + */ + pthread_self :: proc() -> pthread_t --- + + /* + Atomically set the calling thread's cancelability and return the previous value. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setcancelstate.html ]] + */ + pthread_setcancelstate :: proc(state: Cancel_State, oldstate: ^Cancel_State) -> Errno --- + + /* + Atomically set the calling thread's cancel type and return the previous value. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setcancelstate.html ]] + */ + pthread_setcanceltype :: proc(type: Cancel_Type, oldtype: ^Cancel_Type) -> Errno --- + + + /* + Creates a cancellation point in the calling thread. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_testcancel.html ]] + */ + pthread_testcancel :: proc() --- + + /* + Sets the scheduling priority for the thread given. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setschedprio.html ]] + */ + pthread_setschedprio :: proc(thread: pthread_t, prio: c.int) -> Errno --- +} + +Detach_State :: enum c.int { + // Causes all threads to be in the joinable state. + CREATE_JOINABLE = PTHREAD_CREATE_JOINABLE, + // Causes all threads to be in the detached state. + CREATE_DETACHED = PTHREAD_CREATE_DETACHED, +} + +Inherit_Sched :: enum c.int { + // Threads inherit from the creating thread. + INHERIT_SCHED = PTHREAD_INHERIT_SCHED, + // Threads scheduling shall be set to the corresponding values from the attributes object. + EXPLICIT_SCHED = PTHREAD_EXPLICIT_SCHED, +} + +Thread_Scope :: enum c.int { + // System scheduling contention scope. + SYSTEM = PTHREAD_SCOPE_SYSTEM, + // Process scheduling contention scope. + PROCESS = PTHREAD_SCOPE_PROCESS, +} + +Cancel_State :: enum c.int { + ENABLE = PTHREAD_CANCEL_ENABLE, + DISABLE = PTHREAD_CANCEL_DISABLE, +} + +Cancel_Type :: enum c.int { + DEFERRED = PTHREAD_CANCEL_DEFERRED, + ASYNCHRONOUS = PTHREAD_CANCEL_ASYNCHRONOUS, +} + +when ODIN_OS == .Darwin { + + PTHREAD_CANCEL_ASYNCHRONOUS :: 0x00 + PTHREAD_CANCEL_DEFERRED :: 0x02 + + PTHREAD_CANCEL_DISABLE :: 0x00 + PTHREAD_CANCEL_ENABLE :: 0x01 + + PTHREAD_CANCELED :: rawptr(uintptr(1)) + + PTHREAD_CREATE_DETACHED :: 2 + PTHREAD_CREATE_JOINABLE :: 1 + + PTHREAD_EXPLICIT_SCHED :: 2 + PTHREAD_INHERIT_SCHED :: 1 + + PTHREAD_PRIO_INHERIT :: 1 + PTHREAD_PRIO_NONE :: 0 + PTHREAD_PRIO_PROTECT :: 2 + + PTHREAD_PROCESS_SHARED :: 1 + PTHREAD_PROCESS_PRIVATE :: 2 + + PTHREAD_SCOPE_PROCESS :: 2 + PTHREAD_SCOPE_SYSTEM :: 1 + + pthread_t :: distinct u64 + + pthread_attr_t :: struct { + __sig: c.long, + __opaque: [56]c.char, + } + + pthread_key_t :: distinct c.ulong + + sched_param :: struct { + sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */ + _: [4]c.char, + } + +} else when ODIN_OS == .FreeBSD { + + PTHREAD_CANCEL_ASYNCHRONOUS :: 0x02 + PTHREAD_CANCEL_DEFERRED :: 0x00 + + PTHREAD_CANCEL_DISABLE :: 0x01 + PTHREAD_CANCEL_ENABLE :: 0x00 + + PTHREAD_CANCELED :: rawptr(uintptr(1)) + + PTHREAD_CREATE_DETACHED :: 1 + PTHREAD_CREATE_JOINABLE :: 0 + + PTHREAD_EXPLICIT_SCHED :: 0 + PTHREAD_INHERIT_SCHED :: 4 + + PTHREAD_PRIO_INHERIT :: 1 + PTHREAD_PRIO_NONE :: 0 + PTHREAD_PRIO_PROTECT :: 2 + + PTHREAD_PROCESS_SHARED :: 0 + PTHREAD_PROCESS_PRIVATE :: 1 + + PTHREAD_SCOPE_PROCESS :: 0 + PTHREAD_SCOPE_SYSTEM :: 2 + + pthread_t :: distinct u64 + + pthread_attr_t :: distinct rawptr + + pthread_key_t :: distinct c.int + + sched_param :: struct { + sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */ + } + +} else when ODIN_OS == .NetBSD { + + PTHREAD_CANCEL_ASYNCHRONOUS :: 1 + PTHREAD_CANCEL_DEFERRED :: 0 + + PTHREAD_CANCEL_DISABLE :: 1 + PTHREAD_CANCEL_ENABLE :: 0 + + PTHREAD_CANCELED :: rawptr(uintptr(1)) + + PTHREAD_CREATE_DETACHED :: 1 + PTHREAD_CREATE_JOINABLE :: 0 + + PTHREAD_EXPLICIT_SCHED :: 1 + PTHREAD_INHERIT_SCHED :: 0 + + PTHREAD_PRIO_INHERIT :: 1 + PTHREAD_PRIO_NONE :: 0 + PTHREAD_PRIO_PROTECT :: 2 + + PTHREAD_PROCESS_SHARED :: 1 + PTHREAD_PROCESS_PRIVATE :: 0 + + PTHREAD_SCOPE_PROCESS :: 0 + PTHREAD_SCOPE_SYSTEM :: 1 + + pthread_t :: distinct rawptr + + pthread_attr_t :: struct { + pta_magic: c.uint, + pta_flags: c.int, + pta_private: rawptr, + } + + pthread_key_t :: distinct c.int + + sched_param :: struct { + sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */ + } + +} else when ODIN_OS == .OpenBSD { + + PTHREAD_CANCEL_ASYNCHRONOUS :: 2 + PTHREAD_CANCEL_DEFERRED :: 0 + + PTHREAD_CANCEL_DISABLE :: 1 + PTHREAD_CANCEL_ENABLE :: 0 + + PTHREAD_CANCELED :: rawptr(uintptr(1)) + + PTHREAD_CREATE_DETACHED :: 0x1 + PTHREAD_CREATE_JOINABLE :: 0 + + PTHREAD_EXPLICIT_SCHED :: 0 + PTHREAD_INHERIT_SCHED :: 0x4 + + PTHREAD_PRIO_INHERIT :: 1 + PTHREAD_PRIO_NONE :: 0 + PTHREAD_PRIO_PROTECT :: 2 + + PTHREAD_PROCESS_SHARED :: 0 + PTHREAD_PROCESS_PRIVATE :: 1 + + PTHREAD_SCOPE_PROCESS :: 0 + PTHREAD_SCOPE_SYSTEM :: 0x2 + + pthread_t :: distinct rawptr + pthread_attr_t :: distinct rawptr + pthread_key_t :: distinct c.int + + sched_param :: struct { + sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */ + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/pwd.odin b/core/sys/posix/pwd.odin new file mode 100644 index 000000000..546d58309 --- /dev/null +++ b/core/sys/posix/pwd.odin @@ -0,0 +1,168 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// pwd.h - password structure + +foreign lib { + /* + Rewinds the user database so that the next getpwent() returns the first entry. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpwent.html ]] + */ + setpwent :: proc() --- + + /* + Returns the current entry in the user database. + + Returns: nil (setting errno) on error, nil (not setting errno) on success. + + Example: + posix.setpwent() + defer posix.endpwent() + for e := posix.getpwent(); e != nil; e = posix.getpwent() { + fmt.println(e) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpwent.html ]] + */ + @(link_name=LGETPWENT) + getpwent :: proc() -> ^passwd --- + + /* + Closes the user database. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpwent.html ]] + */ + endpwent :: proc() --- + + /* + Searches the database for an entry with a matching name. + + Returns: nil (setting errno) on error, nil (not setting errno) on success. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwnam.html ]] + */ + @(link_name=LGETPWNAM) + getpwnam :: proc(name: cstring) -> ^passwd --- + + /* + Searches the database for an entry with a matching name. + Populating the pwd fields and using the buffer to allocate strings into. + Setting result to nil on failure and to the address of pwd otherwise. + + ERANGE will be returned if there is not enough space in buffer. + sysconf(_SC_GETPW_R_SIZE_MAX) can be called for the suggested size of this buffer, note that it could return -1. + + Example: + length := posix.sysconf(._GETPW_R_SIZE_MAX) + length = length == -1 ? 1024 : length + + buffer: [dynamic]byte + defer delete(buffer) + + result: posix.passwd + resultp: ^posix.passwd + errno: posix.Errno + for { + if err := resize(&buffer, length); err != nil { + fmt.panicf("allocation failure: %v", err) + } + + errno = posix.getpwnam_r("root", &result, raw_data(buffer), len(buffer), &resultp) + if errno != .ERANGE { + break + } + } + + if errno != .NONE { + panic(string(posix.strerror(errno))) + } + + fmt.println(result) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwnam.html ]] + */ + @(link_name=LGETPWNAMR) + getpwnam_r :: proc(name: cstring, pwd: ^passwd, buffer: [^]byte, bufsize: c.size_t, result: ^^passwd) -> Errno --- + + /* + Searches the database for an entry with a matching uid. + + Returns: nil (setting errno) on error, nil (not setting errno) on success. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid.html ]] + */ + @(link_name=LGETPWUID) + getpwuid :: proc(uid: uid_t) -> ^passwd --- + + /* + Searches the database for an entry with a matching uid. + Populating the pwd fields and using the buffer to allocate strings into. + Setting result to nil on failure and to the address of pwd otherwise. + + ERANGE will be returned if there is not enough space in buffer. + sysconf(_SC_GETPW_R_SIZE_MAX) can be called for the suggested size of this buffer, note that it could return -1. + + See the example for getpwnam_r. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html ]] + */ + @(link_name=LGETPWUIDR) + getpwuid_r :: proc(uid: uid_t, pwd: ^passwd, buffer: [^]byte, bufsize: c.size_t, result: ^^passwd) -> Errno --- +} + +when ODIN_OS == .NetBSD { + @(private) LGETPWENT :: "__getpwent50" + @(private) LGETPWNAM :: "__getpwnam50" + @(private) LGETPWNAMR :: "__getpwnam_r50" + @(private) LGETPWUID :: "__getpwuid50" + @(private) LGETPWUIDR :: "__getpwuid_r50" +} else { + @(private) LGETPWENT :: "getpwent" + @(private) LGETPWNAM :: "getpwnam" + @(private) LGETPWNAMR :: "getpwnam_r" + @(private) LGETPWUID :: "getpwuid" + @(private) LGETPWUIDR :: "getpwuid_r" +} + +when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + passwd :: struct { + pw_name: cstring, /* [PSX] user name */ + pw_passwd: cstring, /* encrypted password */ + pw_uid: uid_t, /* [PSX] user uid */ + pw_gid: gid_t, /* [PSX] user gid */ + pw_change: time_t, /* password change time */ + pw_class: cstring, /* user access class */ + pw_gecos: cstring, /* Honeywell login info */ + pw_dir: cstring, /* [PSX] home directory */ + pw_shell: cstring, /* [PSX] default shell */ + pw_expire: time_t, /* account expiration */ + } + +} else when ODIN_OS == .FreeBSD { + + passwd :: struct { + pw_name: cstring, /* [PSX] user name */ + pw_passwd: cstring, /* encrypted password */ + pw_uid: uid_t, /* [PSX] user uid */ + pw_gid: gid_t, /* [PSX] user gid */ + pw_change: time_t, /* password change time */ + pw_class: cstring, /* user access class */ + pw_gecos: cstring, /* Honeywell login info */ + pw_dir: cstring, /* [PSX] home directory */ + pw_shell: cstring, /* [PSX] default shell */ + pw_expire: time_t, /* account expiration */ + pw_fields: c.int, + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sched.odin b/core/sys/posix/sched.odin new file mode 100644 index 000000000..6623ba6e6 --- /dev/null +++ b/core/sys/posix/sched.odin @@ -0,0 +1,105 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sched.h - execution scheduling + +foreign lib { + /* + Returns the minimum for the given scheduling policy. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_get_priority_max.html ]] + */ + sched_get_priority_max :: proc(policy: Sched_Policy) -> c.int --- + + /* + Returns the maximum for the given scheduling policy. + + Returns: -1 (setting errno) on failure, the maximum on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_get_priority_max.html ]] + */ + sched_get_priority_min :: proc(policy: Sched_Policy) -> c.int --- + + /* + Forces the running thread to relinquish the processor until it again becomes the head of its thread list. + */ + sched_yield :: proc() -> result --- + + /* NOTE: unimplemented on darwin (I think?). + /* + Get the scheduling params of a process, pid of 0 will return that of the current process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_getparam.html ]] + */ + sched_getparam :: proc(pid: pid_t, param: ^sched_param) -> result --- + /* + Sets the scheduling parameters of the given process, pid of 0 will set that of the current process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_setparam.html ]] + */ + sched_setparam :: proc(pid: pid_t, param: ^sched_param) -> result --- + + /* + Returns the scheduling policy of a process, pid of 0 will return that of the current process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_getscheduler.html ]] + */ + sched_getscheduler :: proc(pid: pid_t) -> Sched_Policy --- + + /* + Sets the scheduling policy and parameters of the process, pid 0 will be the current process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_setscheduler.html ]] + */ + sched_setscheduler :: proc(pid: pid_t, policy: Sched_Policy, param: ^sched_param) -> result --- + + /* + Updates the timespec structure to contain the current execution time limit for the process. + pid of 0 will return that of the current process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_rr_get_interval.html ]] + */ + sched_rr_get_interval :: proc(pid: pid_t, interval: ^timespec) -> result --- + */ +} + +Sched_Policy :: enum c.int { + // Error condition of sched_getscheduler. + ERROR = -1, + // First in-first out (FIFO) scheduling policy. + FIFO = SCHED_FIFO, + // Round robin scheduling policy. + RR = SCHED_RR, + // Another scheduling policy. + OTHER = SCHED_OTHER, +} + +when ODIN_OS == .Darwin { + + SCHED_FIFO :: 4 + SCHED_RR :: 2 + // SCHED_SPORADIC :: 3 NOTE: not a thing on freebsd, netbsd and probably others, leaving it out + SCHED_OTHER :: 1 + +} else when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD { + + SCHED_FIFO :: 1 + SCHED_RR :: 3 + SCHED_OTHER :: 2 + +} else when ODIN_OS == .NetBSD { + + SCHED_OTHER :: 0 + SCHED_FIFO :: 1 + SCHED_RR :: 2 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/setjmp.odin b/core/sys/posix/setjmp.odin new file mode 100644 index 000000000..cb1dad184 --- /dev/null +++ b/core/sys/posix/setjmp.odin @@ -0,0 +1,58 @@ +package posix + +import "core:c" +import "core:c/libc" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// setjmp.h - stack environment declarations + +foreign lib { + /* + Equivalent to longjmp() but must not touch signals. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/_longjmp.html ]] + */ + _longjmp :: proc(env: ^jmp_buf, val: c.int) -> ! --- + + /* + Equivalent to setjmp() but must not touch signals. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/_longjmp.html ]] + */ + _setjmp :: proc(env: ^jmp_buf) -> c.int --- + + /* + Equivalent to longjmp() but restores saved signal masks. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/siglongjump.html ]] + */ + @(link_name=LSIGLONGJMP) + siglongjmp :: proc(env: ^sigjmp_buf, val: c.int) -> ! --- + + /* + Equivalent to setjmp() but restores saved signal masks. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/siglongjump.html ]] + */ + @(link_name=LSIGSETJMP) + sigsetjmp :: proc(env: ^sigjmp_buf, savemask: b32) -> c.int --- +} + +jmp_buf :: libc.jmp_buf +sigjmp_buf :: distinct jmp_buf + +longjmp :: libc.longjmp +setjmp :: libc.setjmp + +when ODIN_OS == .NetBSD { + @(private) LSIGSETJMP :: "__sigsetjmp14" + @(private) LSIGLONGJMP :: "__siglongjmp14" +} else { + @(private) LSIGSETJMP :: "sigsetjmp" + @(private) LSIGLONGJMP :: "siglongjmp" +} diff --git a/core/sys/posix/signal.odin b/core/sys/posix/signal.odin new file mode 100644 index 000000000..3bfd662f0 --- /dev/null +++ b/core/sys/posix/signal.odin @@ -0,0 +1,1131 @@ +package posix + +import "base:intrinsics" + +import "core:c" +import "core:c/libc" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// signal.h - signals + +foreign lib { + // LIBC: + + /* + Set a signal handler. + + func can either be: + - `auto_cast posix.SIG_DFL` setting the default handler for that specific signal + - `auto_cast posix.SIG_IGN` causing the specific signal to be ignored + - a custom signal handler + + Returns: SIG_ERR (setting errno), the last value of func on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html ]] + */ + signal :: proc(sig: Signal, func: proc "c" (Signal)) -> proc "c" (Signal) --- + + /* + Raises a signal, calling its handler and then returning. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html ]] + */ + raise :: proc(sig: Signal) -> result --- + + // POSIX: + + /* + Raise a signal to the process/group specified by pid. + + If sig is 0, this function can be used to check if the pid is just checked for validity. + + If pid is -1, the signal is sent to all processes that the current process has permission to send. + + If pid is negative (not -1), the signal is sent to all processes in the group identifier by the + absolute value. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/kill.html ]] + */ + kill :: proc(pid: pid_t, sig: Signal) -> result --- + + /* + Shorthand for `kill(-pgrp, sig)` which will kill all processes in the given process group. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html ]] + */ + killpg :: proc(pgrp: pid_t, sig: Signal) -> result --- + + /* + Writes a language-dependent message to stderror. + + Example: + posix.psignal(.SIGSEGV, "that didn't go well") + + Possible Output: + that didn't go well: Segmentation fault + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/psignal.html ]] + */ + psignal :: proc(signum: Signal, message: cstring) --- + + /* + Send a signal to a thread. + + As with kill, if sig is 0, only validation (of the pthread_t given) is done and no signal is sent. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_kill.html ]] + */ + pthread_kill :: proc(thread: pthread_t, sig: Signal) -> Errno --- + + /* + Examine and change blocked signals. + + Equivalent to sigprocmask(), without the restriction that the call be made in a single-threaded process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html ]] + */ + pthread_sigmask :: proc(how: Sig, set: ^sigset_t, oset: ^sigset_t) -> Errno --- + + /* + Examine and change blocked signals in a single-threaded process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html ]] + */ + @(link_name=LSIGPROCMASK) + sigprocmask :: proc(how: Sig, set: ^sigset_t, oldset: ^sigset_t) -> result --- + + /* + Examine and change a signal action. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html ]] + */ + @(link_name=LSIGACTION) + sigaction :: proc(sig: Signal, act: ^sigaction_t, oact: ^sigaction_t) -> result --- + + @(link_name=LSIGADDSET) + sigaddset :: proc(set: ^sigset_t, signo: Signal) -> result --- + @(link_name=LSIGDELSET) + sigdelset :: proc(^sigset_t, Signal) -> c.int --- + @(link_name=LSIGEMPTYSET) + sigemptyset :: proc(^sigset_t) -> c.int --- + @(link_name=LSIGFILLSET) + sigfillset :: proc(^sigset_t) -> c.int --- + + /* + Set and get the signal alternate stack context. + + Example: + sigstk := posix.stack_t { + ss_sp = make([^]byte, posix.SIGSTKSZ) or_else panic("allocation failure"), + ss_size = posix.SIGSTKSZ, + ss_flags = {}, + } + if posix.sigaltstack(&sigstk, nil) != .OK { + fmt.panicf("sigaltstack failure: %v", posix.strerror(posix.errno())) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaltstack.html ]] + */ + @(link_name=LSIGALTSTACK) + sigaltstack :: proc(ss: ^stack_t, oss: ^stack_t) -> result --- + + /* + Adds sig to the signal mask of the calling process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sighold.html ]] + */ + sighold :: proc(sig: Signal) -> result --- + + /* + Sets the disposition of sig to SIG_IGN. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sighold.html ]] + */ + sigignore :: proc(sig: Signal) -> result --- + + /* + Removes sig from the signal mask of the calling process and suspend the calling process until + a signal is received. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sighold.html ]] + */ + sigpause :: proc(sig: Signal) -> result --- + + /* + Removes sig from the signal mask of the calling process. + + Returns: always -1. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sighold.html ]] + */ + sigrelse :: proc(sig: Signal) -> result --- + + /* + Changes the restart behavior when a function is interrupted by the specified signal. + + If flag is true, SA_RESTART is removed, added otherwise. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/siginterrupt.html ]] + */ + siginterrupt :: proc(sig: Signal, flag: b32) -> result --- + + /* + Test for a signal in a signal set. + + Returns: 1 if it is a member, 0 if not, -1 (setting errno) on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigismember.html ]] + */ + @(link_name=LSIGISMEMBER) + sigismember :: proc(set: ^sigset_t, signo: Signal) -> c.int --- + + /* + Stores the set of signals that are blocked from delivery to the calling thread and that are pending + on the process or the calling thread. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigpending.html ]] + */ + @(link_name=LSIGPENDING) + sigpending :: proc(set: ^sigset_t) -> result --- + + /* + Wait for one of the given signals. + + Returns: always -1 + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigsuspend.html ]] + */ + @(link_name=LSIGSUSPEND) + sigsuspend :: proc(sigmask: ^sigset_t) -> result --- + + /* + Wait for queued signals. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigwait.html ]] + */ + sigwait :: proc(set: ^sigset_t, sig: ^Signal) -> Errno --- + + /* NOTE: unimplemented on darwin. + + void psiginfo(const siginfo_t *, const char *); + int sigqueue(pid_t, int, union sigval); + void (*sigset(int, void (*)(int)))(int); + int sigsuspend(const sigset_t *); + int sigtimedwait(const sigset_t *restrict, siginfo_t *restrict, + const struct timespec *restrict); + int sigwaitinfo(const sigset_t *restrict, siginfo_t *restrict); + */ +} + +sigval :: struct #raw_union { + sigval_int: c.int, /* [PSX] integer signal value */ + sigval_ptr: rawptr, /* [PSX] pointer signal value */ +} + +Signal :: enum c.int { + NONE, + + // LIBC: + + // Process abort signal. + SIGABRT = SIGABRT, + // Erronous arithemtic operation. + SIGFPE = SIGFPE, + // Illegal instruction. + SIGILL = SIGILL, + // Terminal interrupt signal. + SIGINT = SIGINT, + // Invalid memory reference. + SIGSEGV = SIGSEGV, + // Termination signal. + SIGTERM = SIGTERM, + + // POSIX: + + // Process abort signal. + SIGALRM = SIGALRM, + // Access to an undefined portion of a memory object. + SIGBUS = SIGBUS, + // Child process terminated, stopped, or continued. + SIGCHLD = SIGCHLD, + // Continue execution, if stopped. + SIGCONT = SIGCONT, + // Hangup. + SIGHUP = SIGHUP, + // Kill (cannot be caught or ignored). + SIGKILL = SIGKILL, + // Write on a pipe with no one to read it. + SIGPIPE = SIGPIPE, + // Terminal quit signal. + SIGQUIT = SIGQUIT, + // Stop executing (cannot be caught or ignored). + SIGSTOP = SIGSTOP, + // Terminal stop process. + SIGTSTP = SIGTSTP, + // Background process attempting read. + SIGTTIN = SIGTTIN, + // Background process attempting write. + SIGTTOU = SIGTTOU, + // User-defined signal 1. + SIGUSR1 = SIGUSR1, + // User-defined signal 2. + SIGUSR2 = SIGUSR2, + // Pollable event. + SIGPOLL = SIGPOLL, + // Profiling timer expired. + SIGPROF = SIGPROF, + // Bad system call. + SIGSYS = SIGSYS, + // Trace/breakpoint trap. + SIGTRAP = SIGTRAP, + // High bandwidth data is available at a socket. + SIGURG = SIGURG, + // Virtual timer expired. + SIGVTALRM = SIGVTALRM, + // CPU time limit exceeded. + SIGXCPU = SIGXCPU, + // File size limit exceeded. + SIGXFSZ = SIGXFSZ, +} + +ILL_Code :: enum c.int { + // Illegal opcode. + ILLOPC = ILL_ILLOPC, + // Illegal operand. + ILLOPN = ILL_ILLOPN, + // Illegal addressing mode. + ILLADR = ILL_ILLADR, + // Illegal trap. + ILLTRP = ILL_ILLTRP, + // Priviledged opcode. + PRVOPC = ILL_PRVOPC, + // Priviledged register. + PRVREG = ILL_PRVREG, + // Coprocessor error. + COPROC = ILL_COPROC, + // Internal stack error. + BADSTK = ILL_BADSTK, +} + +FPE_Code :: enum c.int { + // Integer divide by zero. + INTDIV = FPE_INTDIV, + // Integer overflow. + INTOVF = FPE_INTOVF, + // Floating-point divide by zero. + FLTDIV = FPE_FLTDIV, + // Floating-point overflow. + FLTOVF = FPE_FLTOVF, + // Floating-point underflow. + FLTUND = FPE_FLTUND, + // Floating-point inexact result. + FLTRES = FPE_FLTRES, + // Invalid floating-point operation. + FLTINV = FPE_FLTINV, + // Subscript out of range. + FLTSUB = FPE_FLTSUB, +} + +SEGV_Code :: enum c.int { + // Address not mapped to object. + MAPERR = SEGV_MAPERR, + // Invalid permissions for mapped object. + ACCERR = SEGV_ACCERR, +} + +BUS_Code :: enum c.int { + // Invalid address alignment. + ADRALN = BUS_ADRALN, + // Nonexistent physical address. + ADRERR = BUS_ADRERR, + // Object-specific hardware error. + OBJERR = BUS_OBJERR, +} + +TRAP_Code :: enum c.int { + // Process breakpoint. + BRKPT = TRAP_BRKPT, + // Process trace trap. + TRACE = TRAP_TRACE, +} + +CLD_Code :: enum c.int { + // Child has exited.. + EXITED = CLD_EXITED, + // Child has terminated abnormally and did not create a core file. + KILLED = CLD_KILLED, + // Child has terminated abnormally and created a core file. + DUMPED = CLD_DUMPED, + // Traced child trapped. + TRAPPED = CLD_TRAPPED, + // Child has stopped. + STOPPED = CLD_STOPPED, + // Stopped child has continued. + CONTINUED = CLD_CONTINUED, +} + +POLL_Code :: enum c.int { + // Data input is available. + IN = POLL_IN, + // Output buffers available. + OUT = POLL_OUT, + // Input message available. + MSG = POLL_MSG, + // I/O error. + ERR = POLL_ERR, + // High priority input available. + PRI = POLL_PRI, + // Device disconnected. + HUP = POLL_HUP, +} + +Any_Code :: enum c.int { + // Signal sent by kill(). + USER = SI_USER, + // Signal sent by sigqueue(). + QUEUE = SI_QUEUE, + // Signal generated by expiration of a timer set by timer_settime(). + TIMER = SI_TIMER, + // Signal generated by completion of an asynchronous I/O request. + ASYNCIO = SI_ASYNCIO, + // Signal generated by arrival of a message on an empty message queue. + MESGQ = SI_MESGQ, +} + +SA_Flags_Bits :: enum c.int { + // Do not generate SIGCHLD when children stop or stopped children continue. + NOCLDSTOP = log2(SA_NOCLDSTOP), + // Cause signal delivery to occur on an alternate stack. + ONSTACK = log2(SA_ONSTACK), + // Cause signal disposition to be set to SIG_DFL on entry to signal handlers. + RESETHAND = log2(SA_RESETHAND), + // Cause certain functions to become restartable. + RESTART = log2(SA_RESTART), + // Cause extra information to be passed to signal handlers at the time of receipt of a signal. + SIGINFO = log2(SA_SIGINFO), + // Cause implemention not to create zombie processes or status information on child termination. + NOCLDWAIT = log2(SA_NOCLDWAIT), + // Cause signal not to be automatically blocked on entry to signal handler. + SA_NODEFER = log2(SA_NODEFER), +} +SA_Flags :: bit_set[SA_Flags_Bits; c.int] + +SS_Flag_Bits :: enum c.int { + // Process is executing on an alternate signal stack. + ONSTACK = log2(SS_ONSTACK), + // Alternate signal stack is disabled. + DISABLE = log2(SS_DISABLE), +} +SS_Flags :: bit_set[SS_Flag_Bits; c.int] + +Sig :: enum c.int { + // Resulting set is the union of the current set and the signal set and the complement of + // the signal set pointed to by the argument. + BLOCK = SIG_BLOCK, + // Resulting set is the intersection of the current set and the complement of the signal set + // pointed to by the argument. + UNBLOCK = SIG_UNBLOCK, + // Resulting set is the signal set pointed to by the argument. + SETMASK = SIG_SETMASK, +} + +// Request for default signal handling. +SIG_DFL :: libc.SIG_DFL +// Return value from signal() in case of error. +SIG_ERR :: libc.SIG_ERR +// Request that signal be ignored. +SIG_IGN :: libc.SIG_IGN + +SIGABRT :: libc.SIGABRT +SIGFPE :: libc.SIGFPE +SIGILL :: libc.SIGILL +SIGINT :: libc.SIGINT +SIGSEGV :: libc.SIGSEGV +SIGTERM :: libc.SIGTERM + +when ODIN_OS == .NetBSD { + @(private) LSIGPROCMASK :: "__sigprocmask14" + @(private) LSIGACTION :: "__sigaction_siginfo" + @(private) LSIGADDSET :: "__sigaddset14" + @(private) LSIGDELSET :: "__sigdelset14" + @(private) LSIGEMPTYSET :: "__sigemptyset14" + @(private) LSIGFILLSET :: "__sigfillset14" + @(private) LSIGALTSTACK :: "__sigaltstack14" + @(private) LSIGISMEMBER :: "__sigismember14" + @(private) LSIGPENDING :: "__sigpending14" + @(private) LSIGSUSPEND :: "__sigsuspend14" +} else { + @(private) LSIGPROCMASK :: "sigprocmask" + @(private) LSIGACTION :: "sigaction" + @(private) LSIGADDSET :: "sigaddset" + @(private) LSIGDELSET :: "sigdelset" + @(private) LSIGEMPTYSET :: "sigemptyset" + @(private) LSIGFILLSET :: "sigfillset" + @(private) LSIGALTSTACK :: "sigaltstack" + @(private) LSIGISMEMBER :: "sigismember" + @(private) LSIGPENDING :: "sigpending" + @(private) LSIGSUSPEND :: "sigsuspend" +} + +when ODIN_OS == .Darwin { + + // Request that signal be held + SIG_HOLD :: rawptr(uintptr(5)) + + uid_t :: distinct c.uint32_t + sigset_t :: distinct c.uint32_t + + // MOTE: unimplemented on darwin. + // + // SIGRTMIN :: + // SIGRTMAX :: + + SIGHUP :: 1 + SIGQUIT :: 3 + SIGTRAP :: 5 + SIGPOLL :: 7 + SIGKILL :: 9 + SIGBUS :: 10 + SIGSYS :: 12 + SIGPIPE :: 13 + SIGALRM :: 14 + SIGURG :: 16 + SIGCONT :: 19 + SIGSTOP :: 17 + SIGTSTP :: 18 + SIGCHLD :: 20 + SIGTTIN :: 21 + SIGTTOU :: 22 + SIGXCPU :: 24 + SIGXFSZ :: 25 + SIGVTALRM :: 26 + SIGPROF :: 27 + SIGUSR1 :: 30 + SIGUSR2 :: 31 + + // NOTE: this is actually defined as `sigaction`, but due to the function with the same name + // `_t` has been added. + + sigaction_t :: struct { + using _: struct #raw_union { + sa_handler: proc "c" (Signal), /* [PSX] signal-catching function or one of the SIG_IGN or SIG_DFL */ + sa_sigaction: proc "c" (Signal, ^siginfo_t, rawptr), /* [PSX] signal-catching function */ + }, + sa_mask: sigset_t, /* [PSX] set of signals to be blocked during execution of the signal handling function */ + sa_flags: SA_Flags, /* [PSX] special flags */ + } + + SIG_BLOCK :: 1 + SIG_UNBLOCK :: 2 + SIG_SETMASK :: 3 + + SA_NOCLDSTOP :: 0x0008 + SA_ONSTACK :: 0x0001 + SA_RESETHAND :: 0x0004 + SA_RESTART :: 0x0002 + SA_SIGINFO :: 0x0040 + SA_NOCLDWAIT :: 0x0020 + SA_NODEFER :: 0x0010 + + SS_ONSTACK :: 0x0001 + SS_DISABLE :: 0x0004 + + MINSIGSTKSZ :: 32768 + SIGSTKSZ :: 131072 + + stack_t :: struct { + ss_sp: rawptr, /* [PSX] stack base or pointer */ + ss_size: c.size_t, /* [PSX] stack size */ + ss_flags: SS_Flags, /* [PSX] flags */ + } + + siginfo_t :: struct { + si_signo: Signal, /* [PSX] signal number */ + si_errno: Errno, /* [PSX] errno value associated with this signal */ + si_code: struct #raw_union { /* [PSX] specific more detailed codes per signal */ + ill: ILL_Code, + fpe: FPE_Code, + segv: SEGV_Code, + bus: BUS_Code, + trap: TRAP_Code, + chld: CLD_Code, + poll: POLL_Code, + any: Any_Code, + }, + si_pid: pid_t, /* [PSX] sending process ID */ + si_uid: uid_t, /* [PSX] real user ID of sending process */ + si_status: c.int, /* [PSX] exit value of signal */ + si_addr: rawptr, /* [PSX] address of faulting instruction */ + si_value: sigval, /* [PSX] signal value */ + si_band: c.long, /* [PSX] band event for SIGPOLL */ + __pad: [7]c.ulong, + } + + ILL_ILLOPC :: 1 + ILL_ILLOPN :: 4 + ILL_ILLADR :: 5 + ILL_ILLTRP :: 2 + ILL_PRVOPC :: 3 + ILL_PRVREG :: 6 + ILL_COPROC :: 7 + ILL_BADSTK :: 8 + + FPE_INTDIV :: 7 + FPE_INTOVF :: 8 + FPE_FLTDIV :: 1 + FPE_FLTOVF :: 2 + FPE_FLTUND :: 3 + FPE_FLTRES :: 4 + FPE_FLTINV :: 5 + FPE_FLTSUB :: 6 + + SEGV_MAPERR :: 1 + SEGV_ACCERR :: 2 + + BUS_ADRALN :: 1 + BUS_ADRERR :: 2 + BUS_OBJERR :: 3 + + TRAP_BRKPT :: 1 + TRAP_TRACE :: 2 + + CLD_EXITED :: 1 + CLD_KILLED :: 2 + CLD_DUMPED :: 3 + CLD_TRAPPED :: 4 + CLD_STOPPED :: 5 + CLD_CONTINUED :: 6 + + POLL_IN :: 1 + POLL_OUT :: 2 + POLL_MSG :: 3 + POLL_ERR :: 4 + POLL_PRI :: 5 + POLL_HUP :: 6 + + SI_USER :: 0x10001 + SI_QUEUE :: 0x10002 + SI_TIMER :: 0x10003 + SI_ASYNCIO :: 0x10004 + SI_MESGQ :: 0x10005 + +} else when ODIN_OS == .FreeBSD { + + // Request that signal be held + SIG_HOLD :: rawptr(uintptr(3)) + + uid_t :: distinct c.uint32_t + + sigset_t :: struct { + __bits: [4]c.uint32_t, + } + + // MOTE: unimplemented on darwin. + // + // SIGRTMIN :: 65 + // SIGRTMAX :: 126 + + SIGHUP :: 1 + SIGQUIT :: 3 + SIGTRAP :: 5 + SIGPOLL :: 7 + SIGKILL :: 9 + SIGBUS :: 10 + SIGSYS :: 12 + SIGPIPE :: 13 + SIGALRM :: 14 + SIGURG :: 16 + SIGCONT :: 19 + SIGSTOP :: 17 + SIGTSTP :: 18 + SIGCHLD :: 20 + SIGTTIN :: 21 + SIGTTOU :: 22 + SIGXCPU :: 24 + SIGXFSZ :: 25 + SIGVTALRM :: 26 + SIGPROF :: 27 + SIGUSR1 :: 30 + SIGUSR2 :: 31 + + // NOTE: this is actually defined as `sigaction`, but due to the function with the same name + // `_t` has been added. + + sigaction_t :: struct { + using _: struct #raw_union { + sa_handler: proc "c" (Signal), /* [PSX] signal-catching function or one of the SIG_IGN or SIG_DFL */ + sa_sigaction: proc "c" (Signal, ^siginfo_t, rawptr), /* [PSX] signal-catching function */ + }, + sa_flags: SA_Flags, /* [PSX] special flags */ + sa_mask: sigset_t, /* [PSX] set of signals to be blocked during execution of the signal handling function */ + } + + SIG_BLOCK :: 1 + SIG_UNBLOCK :: 2 + SIG_SETMASK :: 3 + + SA_NOCLDSTOP :: 0x0008 + SA_ONSTACK :: 0x0001 + SA_RESETHAND :: 0x0004 + SA_RESTART :: 0x0002 + SA_SIGINFO :: 0x0040 + SA_NOCLDWAIT :: 0x0020 + SA_NODEFER :: 0x0010 + + SS_ONSTACK :: 0x0001 + SS_DISABLE :: 0x0004 + + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm32 { + MINSIGSTKSZ :: 1024 * 4 + } else when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 { + MINSIGSTKSZ :: 512 * 4 + } + + SIGSTKSZ :: MINSIGSTKSZ + 32768 + + stack_t :: struct { + ss_sp: rawptr, /* [PSX] stack base or pointer */ + ss_size: c.size_t, /* [PSX] stack size */ + ss_flags: SS_Flags, /* [PSX] flags */ + } + + siginfo_t :: struct { + si_signo: Signal, /* [PSX] signal number */ + si_errno: Errno, /* [PSX] errno value associated with this signal */ + si_code: struct #raw_union { /* [PSX] specific more detailed codes per signal */ + ill: ILL_Code, + fpe: FPE_Code, + segv: SEGV_Code, + bus: BUS_Code, + trap: TRAP_Code, + chld: CLD_Code, + poll: POLL_Code, + any: Any_Code, + }, + si_pid: pid_t, /* [PSX] sending process ID */ + si_uid: uid_t, /* [PSX] real user ID of sending process */ + si_status: c.int, /* [PSX] exit value of signal */ + si_addr: rawptr, /* [PSX] address of faulting instruction */ + si_value: sigval, /* [PSX] signal value */ + using _reason: struct #raw_union { + _fault: struct { + _trapno: c.int, /* machine specific trap code */ + }, + _timer: struct { + _timerid: c.int, + _overrun: c.int, + }, + _mesgq: struct { + _mqd: c.int, + }, + using _poll: struct { + si_band: c.long, /* [PSX] band event for SIGPOLL */ + }, + _capsicum: struct { + _syscall: c.int, /* syscall number for signals delivered as a result of system calls denied by capsicum */ + }, + __spare__: struct { + __spare1__: c.long, + __spare2__: [7]c.int, + }, + }, + } + + ILL_ILLOPC :: 1 + ILL_ILLOPN :: 2 + ILL_ILLADR :: 3 + ILL_ILLTRP :: 4 + ILL_PRVOPC :: 5 + ILL_PRVREG :: 6 + ILL_COPROC :: 7 + ILL_BADSTK :: 8 + + FPE_INTDIV :: 2 + FPE_INTOVF :: 1 + FPE_FLTDIV :: 3 + FPE_FLTOVF :: 4 + FPE_FLTUND :: 5 + FPE_FLTRES :: 6 + FPE_FLTINV :: 7 + FPE_FLTSUB :: 8 + + SEGV_MAPERR :: 1 + SEGV_ACCERR :: 2 + + BUS_ADRALN :: 1 + BUS_ADRERR :: 2 + BUS_OBJERR :: 3 + + TRAP_BRKPT :: 1 + TRAP_TRACE :: 2 + + CLD_EXITED :: 1 + CLD_KILLED :: 2 + CLD_DUMPED :: 3 + CLD_TRAPPED :: 4 + CLD_STOPPED :: 5 + CLD_CONTINUED :: 6 + + POLL_IN :: 1 + POLL_OUT :: 2 + POLL_MSG :: 3 + POLL_ERR :: 4 + POLL_PRI :: 5 + POLL_HUP :: 6 + + SI_USER :: 0x10001 + SI_QUEUE :: 0x10002 + SI_TIMER :: 0x10003 + SI_ASYNCIO :: 0x10004 + SI_MESGQ :: 0x10005 + +} else when ODIN_OS == .NetBSD { + + // Request that signal be held + SIG_HOLD :: rawptr(uintptr(3)) + + uid_t :: distinct c.uint32_t + sigset_t :: struct { + __bits: [4]c.uint32_t, + } + + // MOTE: unimplemented on darwin. + // + // SIGRTMIN :: 33 + // SIGRTMAX :: 63 + + SIGHUP :: 1 + SIGQUIT :: 3 + SIGTRAP :: 5 + SIGPOLL :: 7 + SIGKILL :: 9 + SIGBUS :: 10 + SIGSYS :: 12 + SIGPIPE :: 13 + SIGALRM :: 14 + SIGURG :: 16 + SIGCONT :: 19 + SIGSTOP :: 17 + SIGTSTP :: 18 + SIGCHLD :: 20 + SIGTTIN :: 21 + SIGTTOU :: 22 + SIGXCPU :: 24 + SIGXFSZ :: 25 + SIGVTALRM :: 26 + SIGPROF :: 27 + SIGUSR1 :: 30 + SIGUSR2 :: 31 + + // NOTE: this is actually defined as `sigaction`, but due to the function with the same name + // `_t` has been added. + + sigaction_t :: struct { + using _: struct #raw_union { + sa_handler: proc "c" (Signal), /* [PSX] signal-catching function or one of the SIG_IGN or SIG_DFL */ + sa_sigaction: proc "c" (Signal, ^siginfo_t, rawptr), /* [PSX] signal-catching function */ + }, + sa_mask: sigset_t, /* [PSX] set of signals to be blocked during execution of the signal handling function */ + sa_flags: SA_Flags, /* [PSX] special flags */ + } + + SIG_BLOCK :: 1 + SIG_UNBLOCK :: 2 + SIG_SETMASK :: 3 + + SA_NOCLDSTOP :: 0x0008 + SA_ONSTACK :: 0x0001 + SA_RESETHAND :: 0x0004 + SA_RESTART :: 0x0002 + SA_SIGINFO :: 0x0040 + SA_NOCLDWAIT :: 0x0020 + SA_NODEFER :: 0x0010 + + SS_ONSTACK :: 0x0001 + SS_DISABLE :: 0x0004 + + MINSIGSTKSZ :: 8192 + SIGSTKSZ :: MINSIGSTKSZ + 32768 + + stack_t :: struct { + ss_sp: rawptr, /* [PSX] stack base or pointer */ + ss_size: c.size_t, /* [PSX] stack size */ + ss_flags: SS_Flags, /* [PSX] flags */ + } + + @(private) + lwpid_t :: c.int32_t + + siginfo_t :: struct #raw_union { + si_pad: [128]byte, + using _info: struct { + si_signo: Signal, /* [PSX] signal number */ + si_code: struct #raw_union { /* [PSX] specific more detailed codes per signal */ + ill: ILL_Code, + fpe: FPE_Code, + segv: SEGV_Code, + bus: BUS_Code, + trap: TRAP_Code, + chld: CLD_Code, + poll: POLL_Code, + any: Any_Code, + }, + si_errno: Errno, /* [PSX] errno value associated with this signal */ + // #ifdef _LP64 + /* In _LP64 the union starts on an 8-byte boundary. */ + _pad: c.int, + // #endif + using _reason: struct #raw_union { + using _rt: struct { + _pid: pid_t, + _uid: uid_t, + si_value: sigval, /* [PSX] signal value */ + }, + using _child: struct { + si_pid: pid_t, /* [PSX] sending process ID */ + si_uid: uid_t, /* [PSX] real user ID of sending process */ + si_status: c.int, /* [PSX] exit value of signal */ + _utime: clock_t, + _stime: clock_t, + }, + using _fault: struct { + si_addr: rawptr, /* [PSX] address of faulting instruction */ + _trap: c.int, + _trap2: c.int, + _trap3: c.int, + }, + using _poll: struct { + si_band: c.long, /* [PSX] band event for SIGPOLL */ + _fd: FD, + }, + _syscall: struct { + _sysnum: c.int, + _retval: [2]c.int, + _error: c.int, + _args: [8]c.uint64_t, + }, + _ptrace_state: struct { + _pe_report_event: c.int, + _option: struct #raw_union { + _pe_other_pid: pid_t, + _pe_lwp: lwpid_t, + }, + }, + }, + }, + } + + ILL_ILLOPC :: 1 + ILL_ILLOPN :: 2 + ILL_ILLADR :: 3 + ILL_ILLTRP :: 4 + ILL_PRVOPC :: 5 + ILL_PRVREG :: 6 + ILL_COPROC :: 7 + ILL_BADSTK :: 8 + + FPE_INTDIV :: 1 + FPE_INTOVF :: 2 + FPE_FLTDIV :: 3 + FPE_FLTOVF :: 4 + FPE_FLTUND :: 5 + FPE_FLTRES :: 6 + FPE_FLTINV :: 7 + FPE_FLTSUB :: 8 + + SEGV_MAPERR :: 1 + SEGV_ACCERR :: 2 + + BUS_ADRALN :: 1 + BUS_ADRERR :: 2 + BUS_OBJERR :: 3 + + TRAP_BRKPT :: 1 + TRAP_TRACE :: 2 + + CLD_EXITED :: 1 + CLD_KILLED :: 2 + CLD_DUMPED :: 3 + CLD_TRAPPED :: 4 + CLD_STOPPED :: 5 + CLD_CONTINUED :: 6 + + POLL_IN :: 1 + POLL_OUT :: 2 + POLL_MSG :: 3 + POLL_ERR :: 4 + POLL_PRI :: 5 + POLL_HUP :: 6 + + SI_USER :: 0 + SI_QUEUE :: -1 + SI_TIMER :: -2 + SI_ASYNCIO :: -3 + SI_MESGQ :: -4 + +} else when ODIN_OS == .OpenBSD { + + // Request that signal be held + SIG_HOLD :: rawptr(uintptr(3)) + + uid_t :: distinct c.uint32_t + sigset_t :: distinct c.uint32_t + + SIGHUP :: 1 + SIGQUIT :: 3 + SIGTRAP :: 5 + SIGPOLL :: 7 + SIGKILL :: 9 + SIGBUS :: 10 + SIGSYS :: 12 + SIGPIPE :: 13 + SIGALRM :: 14 + SIGURG :: 16 + SIGCONT :: 19 + SIGSTOP :: 17 + SIGTSTP :: 18 + SIGCHLD :: 20 + SIGTTIN :: 21 + SIGTTOU :: 22 + SIGXCPU :: 24 + SIGXFSZ :: 25 + SIGVTALRM :: 26 + SIGPROF :: 27 + SIGUSR1 :: 30 + SIGUSR2 :: 31 + + // NOTE: this is actually defined as `sigaction`, but due to the function with the same name + // `_t` has been added. + + sigaction_t :: struct { + using _: struct #raw_union { + sa_handler: proc "c" (Signal), /* [PSX] signal-catching function or one of the SIG_IGN or SIG_DFL */ + sa_sigaction: proc "c" (Signal, ^siginfo_t, rawptr), /* [PSX] signal-catching function */ + }, + sa_mask: sigset_t, /* [PSX] set of signals to be blocked during execution of the signal handling function */ + sa_flags: SA_Flags, /* [PSX] special flags */ + } + + SIG_BLOCK :: 1 + SIG_UNBLOCK :: 2 + SIG_SETMASK :: 3 + + SA_NOCLDSTOP :: 0x0008 + SA_ONSTACK :: 0x0001 + SA_RESETHAND :: 0x0004 + SA_RESTART :: 0x0002 + SA_SIGINFO :: 0x0040 + SA_NOCLDWAIT :: 0x0020 + SA_NODEFER :: 0x0010 + + SS_ONSTACK :: 0x0001 + SS_DISABLE :: 0x0004 + + MINSIGSTKSZ :: 3 << 12 + SIGSTKSZ :: MINSIGSTKSZ + (1 << 12) * 4 + + stack_t :: struct { + ss_sp: rawptr, /* [PSX] stack base or pointer */ + ss_size: c.size_t, /* [PSX] stack size */ + ss_flags: SS_Flags, /* [PSX] flags */ + } + + SI_MAXSZ :: 128 + SI_PAD :: (SI_MAXSZ / size_of(c.int)) - 3 + + siginfo_t :: struct { + si_signo: Signal, /* [PSX] signal number */ + si_code: struct #raw_union { /* [PSX] specific more detailed codes per signal */ + ill: ILL_Code, + fpe: FPE_Code, + segv: SEGV_Code, + bus: BUS_Code, + trap: TRAP_Code, + chld: CLD_Code, + poll: POLL_Code, + any: Any_Code, + }, + si_errno: Errno, /* [PSX] errno value associated with this signal */ + using _data: struct #raw_union { + _pad: [SI_PAD]c.int, + using _proc: struct { + si_pid: pid_t, /* [PSX] sending process ID */ + si_uid: uid_t, /* [PSX] real user ID of sending process */ + using _pdata: struct #raw_union { + using _kill: struct { + si_value: sigval, + }, + using _cld: struct { + _utime: clock_t, + _stime: clock_t, + si_status: c.int, + }, + }, + }, + using _fault: struct { + si_addr: rawptr, + _trapno: c.int, + }, + using _file: struct { + _fd: FD, + si_band: c.long, /* [PSX] band event for SIGPOLL */ + }, + }, + } + + ILL_ILLOPC :: 1 + ILL_ILLOPN :: 2 + ILL_ILLADR :: 3 + ILL_ILLTRP :: 4 + ILL_PRVOPC :: 5 + ILL_PRVREG :: 6 + ILL_COPROC :: 7 + ILL_BADSTK :: 8 + + FPE_INTDIV :: 1 + FPE_INTOVF :: 2 + FPE_FLTDIV :: 3 + FPE_FLTOVF :: 4 + FPE_FLTUND :: 5 + FPE_FLTRES :: 6 + FPE_FLTINV :: 7 + FPE_FLTSUB :: 8 + + SEGV_MAPERR :: 1 + SEGV_ACCERR :: 2 + + BUS_ADRALN :: 1 + BUS_ADRERR :: 2 + BUS_OBJERR :: 3 + + TRAP_BRKPT :: 1 + TRAP_TRACE :: 2 + + CLD_EXITED :: 1 + CLD_KILLED :: 2 + CLD_DUMPED :: 3 + CLD_TRAPPED :: 4 + CLD_STOPPED :: 5 + CLD_CONTINUED :: 6 + + POLL_IN :: 1 + POLL_OUT :: 2 + POLL_MSG :: 3 + POLL_ERR :: 4 + POLL_PRI :: 5 + POLL_HUP :: 6 + + SI_USER :: 0 + SI_QUEUE :: -2 + SI_TIMER :: -3 + SI_ASYNCIO :: -4 // NOTE: not implemented + SI_MESGQ :: -5 // NOTE: not implemented + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/stdio.odin b/core/sys/posix/stdio.odin new file mode 100644 index 000000000..de716f8d7 --- /dev/null +++ b/core/sys/posix/stdio.odin @@ -0,0 +1,332 @@ +package posix + +import "core:c" +import "core:c/libc" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// stdio.h - standard buffered input/output + +foreign lib { + /* + Generates a string that, when used as a pathname, + refers to the current controlling terminal for the current process. + + If s is nil, the returned string might be static and overwritten by subsequent calls or other factors. + If s is not nil, s is assumed len(s) >= L_ctermid. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ctermid.html ]] + */ + ctermid :: proc(s: [^]byte) -> cstring --- + + /* + Equivalent to fprintf but output is written to the file descriptor. + + Return: number of bytes written, negative (setting errno) on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dprintf.html ]] + */ + dprintf :: proc(fildse: FD, format: cstring, #c_vararg args: ..any) -> c.int --- + + /* + Equivalent to fprintf but output is written to s, it is the user's responsibility to + ensure there is enough space. + + Return: number of bytes written, negative (setting errno) on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dprintf.html ]] + */ + sprintf :: proc(s: [^]byte, format: cstring, #c_vararg args: ..any) -> c.int --- + + /* + Associate a stream with a file descriptor. + + Returns: nil (setting errno) on failure, the stream on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopen.html ]] + */ + fdopen :: proc(fildes: FD, mode: cstring) -> ^FILE --- + + /* + Map a stream pointer to a file descriptor. + + Returns: the file descriptor or -1 (setting errno) on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fileno.html ]] + */ + fileno :: proc(stream: ^FILE) -> FD --- + + /* + Locks a file. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html ]] + */ + flockfile :: proc(file: ^FILE) --- + + /* + Tries to lock a file. + + Returns: 0 if it could be locked, non-zero if it couldn't + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html ]] + */ + ftrylockfile :: proc(file: ^FILE) -> c.int --- + + /* + Unlocks a file. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html ]] + */ + funlockfile :: proc(file: ^FILE) --- + + /* + Open a memory buffer stream. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fmemopen.html ]] + */ + fmemopen :: proc(buf: [^]byte, size: c.size_t, mode: cstring) -> ^FILE --- + + /* + Reposition a file-position indicator in a stream. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fseeko.html ]] + */ + fseeko :: proc(stream: ^FILE, offset: off_t, whence: Whence) -> result --- + + /* + Return the file offset in a stream. + + Returns: the current file offset, -1 (setting errno) on error + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftello.html ]] + */ + ftello :: proc(^FILE) -> off_t --- + + /* + Open a dynamic memory buffer stream. + + Returns: nil (setting errno) on failure, the stream on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/open_memstream.html ]] + */ + open_memstream :: proc(bufp: ^[^]byte, sizep: ^c.size_t) -> ^FILE --- + + /* + Equivalent to getc but unaffected by locks. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] + */ + getc_unlocked :: proc(stream: ^FILE) -> c.int --- + + /* + Equivalent to getchar but unaffected by locks. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] + */ + getchar_unlocked :: proc() -> c.int --- + + /* + Equivalent to putc but unaffected by locks. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] + */ + putc_unlocked :: proc(ch: c.int, stream: ^FILE) -> c.int --- + + /* + Equivalent to putchar but unaffected by locks. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] + */ + putchar_unlocked :: proc(ch: c.int) -> c.int --- + + /* + Read a delimited record from the stream. + + Returns: the number of bytes written or -1 on failure/EOF + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html ]] + */ + getdelim :: proc(lineptr: ^cstring, n: ^c.size_t, delimiter: c.int, stream: ^FILE) -> c.ssize_t --- + + /* + Read a line delimited record from the stream. + + Returns: the number of bytes written or -1 on failure/EOF + + Example: + fp := posix.fopen(#file, "r") + if fp == nil { + posix.exit(1) + } + + line: cstring + length: uint + for { + read := posix.getline(&line, &length, fp) + if read == -1 do break + posix.printf("Retrieved line of length %zu :\n", read) + posix.printf("%s", line) + } + if posix.ferror(fp) != 0 { + /* handle error */ + } + posix.free(rawptr(line)) + posix.fclose(fp) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html ]] + */ + getline :: proc(lineptr: ^cstring, n: ^c.size_t, stream: ^FILE) -> c.ssize_t --- + + /* + Get a string from the stdin stream. + + It is up to the user to make sure s is big enough. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gets.html ]] + */ + gets :: proc(s: [^]byte) -> cstring --- + + /* + Create a name for a temporary file. + + Returns: an allocated cstring that needs to be freed, nil on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tempnam.html ]] + */ + tempnam :: proc(dir: cstring, pfx: cstring) -> cstring --- + + /* + Executes the command specified, creating a pipe and returning a pointer to a stream that can + read or write from/to the pipe. + + Returns: nil (setting errno) on failure or a pointer to the stream + + Example: + fp := posix.popen("ls *", "r") + if fp == nil { + /* Handle error */ + } + + path: [1024]byte + for posix.fgets(raw_data(path[:]), len(path), fp) != nil { + posix.printf("%s", &path) + } + + status := posix.pclose(fp) + if status == -1 { + /* Error reported by pclose() */ + } else { + /* Use functions described under wait() to inspect `status` in order + to determine success/failure of the command executed by popen() */ + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/popen.html ]] + */ + popen :: proc(command: cstring, mode: cstring) -> ^FILE --- + + /* + Closes a pipe stream to or from a process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pclose.html ]] + */ + pclose :: proc(stream: ^FILE) -> c.int --- + + /* + Equivalent to rename but relative directories are resolved from their respective fds. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/renameat.html ]] + */ + renameat :: proc(oldfd: FD, old: cstring, newfd: FD, new: cstring) -> result --- +} + +clearerr :: libc.clearerr +fclose :: libc.fclose +feof :: libc.feof +ferror :: libc.ferror +fflush :: libc.fflush +fgetc :: libc.fgetc +fgetpos :: libc.fgetpos +fgets :: libc.fgets +fopen :: libc.fopen +fprintf :: libc.fprintf +fputc :: libc.fputc +fread :: libc.fread +freopen :: libc.freopen +fscanf :: libc.fscanf +fseek :: libc.fseek +fsetpos :: libc.fsetpos +ftell :: libc.ftell +fwrite :: libc.fwrite +getc :: libc.getc +getchar :: libc.getchar +perror :: libc.perror +printf :: libc.printf +putc :: libc.puts +putchar :: libc.putchar +puts :: libc.puts +remove :: libc.remove +rename :: libc.rename +rewind :: libc.rewind +scanf :: libc.scanf +setbuf :: libc.setbuf +setvbuf :: libc.setvbuf +snprintf :: libc.snprintf +sscanf :: libc.sscanf +tmpfile :: libc.tmpfile +tmpnam :: libc.tmpnam +vfprintf :: libc.vfprintf +vfscanf :: libc.vfscanf +vprintf :: libc.vprintf +vscanf :: libc.vscanf +vsnprintf :: libc.vsnprintf +vsprintf :: libc.vsprintf +vsscanf :: libc.vsscanf +ungetc :: libc.ungetc + +to_stream :: libc.to_stream + +Whence :: libc.Whence +FILE :: libc.FILE +fpos_t :: libc.fpos_t + +BUFSIZ :: libc.BUFSIZ + +_IOFBF :: libc._IOFBF +_IOLBF :: libc._IOLBF +_IONBF :: libc._IONBF + +SEEK_CUR :: libc.SEEK_CUR +SEEK_END :: libc.SEEK_END +SEEK_SET :: libc.SEEK_SET + +FILENAME_MAX :: libc.FILENAME_MAX +FOPEN_MAX :: libc.FOPEN_MAX +TMP_MAX :: libc.TMP_MAX + +EOF :: libc.EOF + +stderr := libc.stderr +stdin := libc.stdin +stdout := libc.stdout + +when ODIN_OS == .Darwin { + + L_ctermid :: 1024 + L_tmpnam :: 1024 + + P_tmpdir :: "/var/tmp/" + +} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + L_ctermid :: 1024 + L_tmpnam :: 1024 + + P_tmpdir :: "/tmp/" + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/stdlib.odin b/core/sys/posix/stdlib.odin new file mode 100644 index 000000000..a1e2eab50 --- /dev/null +++ b/core/sys/posix/stdlib.odin @@ -0,0 +1,450 @@ +package posix + +import "base:intrinsics" + +import "core:c" +import "core:c/libc" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// stdlib.h - standard library definitions + +atof :: libc.atof +atoi :: libc.atoi +atol :: libc.atol +atoll :: libc.atoll +strtod :: libc.strtod +strtof :: libc.strtof +strtol :: libc.strtol +strtoll :: libc.strtoll +strtoul :: libc.strtoul +strtoull :: libc.strtoull + +rand :: libc.rand +srand :: libc.srand + +calloc :: libc.calloc +malloc :: libc.malloc +realloc :: libc.realloc + +abort :: libc.abort +atexit :: libc.atexit +at_quick_exit :: libc.at_quick_exit +exit :: libc.exit +_Exit :: libc._Exit +getenv :: libc.getenv +quick_exit :: libc.quick_exit +system :: libc.system + +bsearch :: libc.bsearch +qsort :: libc.qsort + +abs :: libc.abs +labs :: libc.labs +llabs :: libc.llabs +div :: libc.div +ldiv :: libc.ldiv +lldiv :: libc.lldiv + +mblen :: libc.mblen +mbtowc :: libc.mbtowc +wctomb :: libc.wctomb + +mbstowcs :: libc.mbstowcs +wcstombs :: libc.wcstombs + +free :: #force_inline proc(ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring { + libc.free(rawptr(ptr)) +} + +foreign lib { + /* + Takes a pointer to a radix-64 representation, in which the first digit is the least significant, + and return the corresponding long value. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/a64l.html ]] + */ + a64l :: proc(s: cstring) -> c.long --- + + /* + The l64a() function shall take a long argument and return a pointer to the corresponding + radix-64 representation. + + Returns: a string that may be invalidated by subsequent calls + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/a64l.html ]] + */ + l64a :: proc(value: c.long) -> cstring --- + + /* + This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic. + + Returns: non-negative, double-precision, floating-point values, uniformly distributed over the interval [0.0,1.0) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]] + */ + drand48 :: proc() -> c.double --- + + /* + This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic. + + Returns: non-negative, double-precision, floating-point values, uniformly distributed over the interval [0.0,1.0) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]] + */ + erand48 :: proc(xsubi: ^[3]c.ushort) -> c.double --- + + /* + This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic. + + Returns: return signed long integers uniformly distributed over the interval [-231,231) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]] + */ + mrand48 :: proc() -> c.long --- + + /* + This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic. + + Returns: return signed long integers uniformly distributed over the interval [-231,231) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]] + */ + jrand48 :: proc(xsubi: ^[3]c.ushort) -> c.long --- + + /* + This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic. + + Returns: non-negative, long integers, uniformly distributed over the interval [0,231) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]] + */ + lrand48 :: proc() -> c.long --- + + /* + This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic. + + Returns: non-negative, long integers, uniformly distributed over the interval [0,231) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]] + */ + nrand48 :: proc(xsubi: ^[3]c.ushort) -> c.long --- + + /* + This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic. + + The srand48(), seed48(), and lcong48() functions are initialization entry points, one of which should be invoked before either drand48(), lrand48(), or mrand48() is called. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]] + */ + srand48 :: proc(seedval: c.long) --- + + /* + This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic. + + The srand48(), seed48(), and lcong48() functions are initialization entry points, one of which should be invoked before either drand48(), lrand48(), or mrand48() is called. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]] + */ + lcong48 :: proc(param: ^[7]c.ushort) --- + + /* + This family of functions shall generate pseudo-random numbers using a linear congruential algorithm and 48-bit integer arithmetic. + + The srand48(), seed48(), and lcong48() functions are initialization entry points, one of which should be invoked before either drand48(), lrand48(), or mrand48() is called. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/drand48.html ]] + */ + seed48 :: proc(seed16v: ^[3]c.ushort) -> ^[3]c.ushort --- + + /* + Parses suboption arguments in a flag argument. + + Returns: the index of the matched token string, or -1 if no token strings were matched + + Example: + args := runtime.args__ + + Opt :: enum { + RO, + RW, + NAME, + NIL, + } + token := [Opt]cstring{ + .RO = "ro", + .RW = "rw", + .NAME = "name", + .NIL = nil, + } + + Options :: struct { + readonly, readwrite: bool, + name: cstring, + + } + opts: Options + + errfnd: bool + for { + opt := posix.getopt(i32(len(args)), raw_data(args), "o:") + if opt == -1 { + break + } + + switch opt { + case 'o': + subopt := posix.optarg + value: cstring + for subopt != "" && !errfnd { + o := posix.getsubopt(&subopt, &token[.RO], &value) + switch Opt(o) { + case .RO: opts.readonly = true + case .RW: opts.readwrite = true + case .NAME: + if value == nil { + fmt.eprintfln("missing value for suboption %s", token[.NAME]) + errfnd = true + continue + } + + opts.name = value + case .NIL: + fallthrough + case: + fmt.eprintfln("no match found for token: %s", value) + errfnd = true + } + } + if opts.readwrite && opts.readonly { + fmt.eprintfln("Only one of %s and %s can be specified", token[.RO], token[.RW]) + errfnd = true + } + case: + errfnd = true + } + } + + if errfnd || len(args) == 1 { + fmt.eprintfln("\nUsage: %s -o ", args[0]) + fmt.eprintfln("suboptions are 'ro', 'rw', and 'name='") + posix.exit(1) + } + + fmt.println(opts) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsubopt.html ]] + */ + getsubopt :: proc(optionp: ^cstring, keylistp: [^]cstring, valuep: ^cstring) -> c.int --- + + /* + Changes the mode and ownership of the slave pseudo-terminal device associated with its master pseudo-terminal counterpart. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html ]] + */ + grantpt :: proc(fildes: FD) -> result --- + + /* + Allows a state array, pointed to by the state argument, to be initialized for future use. + + Returns: the previous state array or nil on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/initstate.html ]] + */ + @(link_name=LINITSTATE) + initstate :: proc(seed: c.uint, state: [^]byte, size: c.size_t) -> [^]byte --- + + /* + Sets the state array of the random number generator. + + Returns: the previous state array or nil on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/initstate.html ]] + */ + setstate :: proc(state: [^]byte) -> [^]byte --- + + /* + Use a non-linear additive feedback random-number generator employing a default state array + size of 31 long integers to return successive pseudo-random numbers in the range from 0 to 231-1. + The period of this random-number generator is approximately 16 x (231-1). + The size of the state array determines the period of the random-number generator. + Increasing the state array size shall increase the period. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/initstate.html ]] + */ + random :: proc() -> c.long --- + + /* + Initializes the current state array using the value of seed. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/initstate.html ]] + */ + @(link_name=LSRANDOM) + srandom :: proc(seed: c.uint) --- + + /* + Creates a directory with a unique name derived from template. + The application shall ensure that the string provided in template is a pathname ending + with at least six trailing 'X' characters. + + Returns: nil (setting errno) on failure, template on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdtemp.html ]] + */ + mkdtemp :: proc(template: [^]byte) -> cstring --- + + /* + Creates a regular file with a unique name derived from template and return a file descriptor + for the file open for reading and writing. + The application shall ensure that the string provided in template is a pathname ending with + at least six trailing 'X' characters. + + Returns: -1 (setting errno) on failure, an open file descriptor on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdtemp.html ]] + */ + mkstemp :: proc(template: cstring) -> FD --- + + /* + Allocates size bytes aligned on a boundary specified by alignment, and shall return a pointer + to the allocated memory in memptr. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_memalign.html ]] + */ + posix_memalign :: proc(memptr: ^[^]byte, alignment: c.size_t, size: c.size_t) -> Errno --- + + /* + Establishes a connection between a master device for a pseudo-terminal and a file descriptor. + + Returns: -1 (setting errno) on failure, an open file descriptor otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html ]] + */ + posix_openpt :: proc(oflag: O_Flags) -> FD --- + + /* + Returns the name of the slave pseudo-terminal device associated with a master pseudo-terminal device. + + Returns: nil (setting errno) on failure, the name on success, which may be invalidated on subsequent calls + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ptsname.html ]] + */ + ptsname :: proc(fildes: FD) -> cstring --- + + /* + Unlocks the slave pseudo-terminal device associated with the master to which fildes refers. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlockpt.html ]] + */ + unlockpt :: proc(fildes: FD) -> result --- + + /* + Uses the string argument to set environment variable values. + + Returns: 0 on success, non-zero (setting errno) on failure + + Example: + if posix.putenv("HOME=/usr/home") != 0 { + fmt.panicf("putenv failure: %v", posix.strerror(posix.errno())) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/putenv.html ]] + */ + @(link_name=LPUTENV) + putenv :: proc(string: cstring) -> c.int --- + + /* + Updates or add a variable in the environment of the calling process. + + Example: + if posix.setenv("HOME", "/usr/home") != .OK { + fmt.panicf("putenv failure: %v", posix.strerror(posix.errno())) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setenv.html ]] + */ + setenv :: proc(envname: cstring, envval: cstring, overwrite: b32) -> result --- + + /* + Removes an environment variable from the environment of the calling process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/unsetenv.html ]] + */ + @(link_name=LUNSETENV) + unsetenv :: proc(name: cstring) -> result --- + + /* + Computes a sequence of pseudo-random integers in the range [0, {RAND_MAX}]. + (The value of the {RAND_MAX} macro shall be at least 32767.) + + If rand_r() is called with the same initial value for the object pointed to by seed and that object is not modified between successive returns and calls to rand_r(), the same sequence shall be generated. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/rand_r.html ]] + */ + rand_r :: proc(seed: ^c.uint) -> c.int --- + + /* + Derive, from the pathname file_name, an absolute pathname that resolves to the same directory entry, + whose resolution does not involve '.', '..', or symbolic links. + + If resolved_name is not `nil` it should be larger than `PATH_MAX` and the result will use it as a backing buffer. + If resolved_name is `nil` the returned string is allocated by `malloc`. + + Returns: `nil` (setting errno) on failure, the "real path" otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html ]] + */ + realpath :: proc(file_name: cstring, resolved_name: [^]byte = nil) -> cstring --- + + /* + Provides access to an implementation-defined encoding algorithm. + The argument of setkey() is an array of length 64 bytes containing only the bytes with numerical + value of 0 and 1. + + If this string is divided into groups of 8, the low-order bit in each group is ignored; this gives a 56-bit key which is used by the algorithm. + This is the key that shall be used with the algorithm to encode a string block passed to encrypt(). + + The setkey() function shall not change the setting of errno if successful. + An application wishing to check for error situations should set errno to 0 before calling setkey(). + If errno is non-zero on return, an error has occurred. + + Example: + key: [64]byte + // set key bytes... + + posix.set_errno(.NONE) + posix.setkey(raw_data(key)) + if errno := posix.errno(); errno != .NONE { + fmt.panicf("setkey failure: %s", posix.strerror(errno)) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setkey.html ]] + */ + setkey :: proc(key: [^]byte) --- +} + +EXIT_FAILURE :: libc.EXIT_FAILURE +EXIT_SUCCESS :: libc.EXIT_SUCCESS + +RAND_MAX :: libc.RAND_MAX +MB_CUR_MAX :: libc.MB_CUR_MAX + +div_t :: libc.div_t +ldiv_t :: libc.ldiv_t +lldiv_t :: libc.lldiv_t + +when ODIN_OS == .NetBSD { + @(private) LPUTENV :: "__putenv50" + @(private) LINITSTATE :: "__initstate60" + @(private) LSRANDOM :: "__srandom60" + @(private) LUNSETENV :: "__unsetenv13" +} else { + @(private) LPUTENV :: "putenv" + @(private) LINITSTATE :: "initstate" + @(private) LSRANDOM :: "srandom" + @(private) LUNSETENV :: "unsetenv" +} diff --git a/core/sys/posix/string.odin b/core/sys/posix/string.odin new file mode 100644 index 000000000..d22f49a96 --- /dev/null +++ b/core/sys/posix/string.odin @@ -0,0 +1,47 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// string.h - string operations + +// NOTE: most of the symbols in this header are not useful in Odin and have been left out. + +foreign lib { + /* + Map the error number to a locale-dependent error message string. + + Returns: a string that may be invalidated by subsequent calls + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html ]] + */ + @(link_name="strerror") + _strerror :: proc(errnum: Errno) -> cstring --- + + /* + Map the error number to a locale-dependent error message string and put it in the buffer. + + Returns: ERANGE if the buffer is not big enough + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror_r.html ]] + */ + strerror_r :: proc(errnum: Errno, strerrbuf: [^]byte, buflen: c.size_t) -> Errno --- + + /* + Map the signal number to an implementation-defined string. + + Returns: a string that may be invalidated by subsequent calls + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strsignal.html ]] + */ + strsignal :: proc(sig: Signal) -> cstring --- +} + +strerror :: #force_inline proc "contextless" (errnum: Maybe(Errno) = nil) -> cstring { + return _strerror(errnum.? or_else errno()) +} diff --git a/core/sys/posix/sys_ipc.odin b/core/sys/posix/sys_ipc.odin new file mode 100644 index 000000000..f8778ee15 --- /dev/null +++ b/core/sys/posix/sys_ipc.odin @@ -0,0 +1,89 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/ipc.h = XSI interprocess communication access structure + +foreign lib { + /* + Generate an IPC key. + + Returns: -1 (setting errno) on failure, the key otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftok.html ]] + */ + ftok :: proc(path: cstring, id: c.int) -> key_t --- +} + +IPC_Cmd :: enum c.int { + RMID = IPC_RMID, + SET = IPC_SET, + STAT = IPC_STAT, +} + +IPC_Flag_Bits :: enum c.int { + CREAT = log2(IPC_CREAT), + EXCL = log2(IPC_EXCL), + NOWAIT = log2(IPC_NOWAIT), + + MSG_NOERROR = log2(MSG_NOERROR), +} +IPC_Flags :: bit_set[IPC_Flag_Bits; c.int] + +when ODIN_OS == .Darwin { + + key_t :: distinct c.int32_t + + ipc_perm :: struct { + uid: uid_t, /* [PSX] owner's user ID */ + gid: gid_t, /* [PSX] owner's group ID */ + cuid: uid_t, /* [PSX] creator's user ID */ + cgid: gid_t, /* [PSX] creator's group ID */ + mode: mode_t, /* [PSX] read/write perms */ + _seq: c.ushort, + _key: key_t, + } + + IPC_CREAT :: 0o01000 + IPC_EXCL :: 0o02000 + IPC_NOWAIT :: 0o04000 + + IPC_PRIVATE :: key_t(0) + + IPC_RMID :: 0 + IPC_SET :: 1 + IPC_STAT :: 2 + +} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + key_t :: distinct c.long + + ipc_perm :: struct { + cuid: uid_t, /* [PSX] creator's user ID */ + cgid: gid_t, /* [PSX] creator's group ID */ + uid: uid_t, /* [PSX] owner's user ID */ + gid: gid_t, /* [PSX] owner's group ID */ + mode: mode_t, /* [PSX] read/write perms */ + _seq: c.ushort, + _key: key_t, + } + + IPC_CREAT :: 0o01000 + IPC_EXCL :: 0o02000 + IPC_NOWAIT :: 0o04000 + + IPC_PRIVATE :: key_t(0) + + IPC_RMID :: 0 + IPC_SET :: 1 + IPC_STAT :: 2 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_mman.odin b/core/sys/posix/sys_mman.odin new file mode 100644 index 000000000..217d321ac --- /dev/null +++ b/core/sys/posix/sys_mman.odin @@ -0,0 +1,229 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// mman.h - memory management declarations + +foreign lib { + /* + Establish a mapping between an address space of a process and a memory object. + + Returns: MAP_FAILED (setting errno) on failure, the address in memory otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html ]] + */ + mmap :: proc( + addr: rawptr, + len: c.size_t, + prot: Prot_Flags, + flags: Map_Flags, + fd: FD = -1, + off: off_t = 0, + ) -> rawptr --- + + /* + Unmaps pages of memory. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/munmap.html ]] + */ + munmap :: proc(addr: rawptr, len: c.size_t) -> result --- + + /* + Locks a range of the process address space. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlock.html ]] + */ + mlock :: proc(addr: rawptr, len: c.size_t) -> result --- + + /* + Unlocks a range of the process address space. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlock.html ]] + */ + munlock :: proc(addr: rawptr, len: c.size_t) -> result --- + + /* + Locks all pages of the process address space. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlockall.html ]] + */ + mlockall :: proc(flags: Lock_Flags) -> result --- + + /* + Unlocks all pages of the process address space. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mlockall.html ]] + */ + munlockall :: proc() -> result --- + + /* + Set protection of a memory mapping. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html ]] + */ + mprotect :: proc(addr: rawptr, len: c.size_t, prot: Prot_Flags) -> result --- + + /* + Write all modified data to permanent storage locations. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/msync.html ]] + */ + @(link_name=LMSYNC) + msync :: proc(addr: rawptr, len: c.size_t, flags: Sync_Flags) -> result --- + + /* + Advise the implementation of expected behavior of the application. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_madvise.html ]] + */ + posix_madvise :: proc(addr: rawptr, len: c.size_t, advice: MAdvice) -> Errno --- + + /* + Open a shared memory object. + + Returns: -1 (setting errno) on failure, an open file descriptor otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_open.html ]] + */ + shm_open :: proc(name: cstring, oflag: O_Flags, mode: mode_t) -> FD --- + + /* + Removes a shared memory object. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_unlink.html ]] + */ + shm_unlink :: proc(name: cstring) -> result --- +} + +#assert(_PROT_NONE == 0) +PROT_NONE :: Prot_Flags{} + +Prot_Flag_Bits :: enum c.int { + // Data can be executed. + EXEC = log2(PROT_EXEC), + // Data can be read. + READ = log2(PROT_READ), + // Data can be written. + WRITE = log2(PROT_WRITE), +} +Prot_Flags :: bit_set[Prot_Flag_Bits; c.int] + +Map_Flag_Bits :: enum c.int { + // Interpret addr exactly. + FIXED = log2(MAP_FIXED), + // Changes are private. + PRIVATE = log2(MAP_PRIVATE), + // Changes are shared. + SHARED = log2(MAP_SHARED), +} +Map_Flags :: bit_set[Map_Flag_Bits; c.int] + +Lock_Flag_Bits :: enum c.int { + // Lock all pages currently mapped into the address space of the process. + CURRENT = log2(MCL_CURRENT), + // Lock all pages that become mapped into the address space of the process in the future, + // when those mappings are established. + FUTURE = log2(MCL_FUTURE), +} +Lock_Flags :: bit_set[Lock_Flag_Bits; c.int] + +Sync_Flags_Bits :: enum c.int { + // Perform asynchronous writes. + ASYNC = log2(MS_ASYNC), + // Invalidate cached data. + INVALIDATE = log2(MS_INVALIDATE), + + // Perform synchronous writes. + // NOTE: use with `posix.MS_SYNC + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in + // this bit set enum because it is 0 on some platforms and a value on others. + // LOCAL = RTLD_LOCAL + // SYNC = MS_SYNC, + + _MAX = 31, +} +Sync_Flags :: bit_set[Sync_Flags_Bits; c.int] + +MAdvice :: enum c.int { + DONTNEED = POSIX_MADV_DONTNEED, + NORMAL = POSIX_MADV_NORMAL, + RANDOM = POSIX_MADV_RANDOM, + SEQUENTIAL = POSIX_MADV_SEQUENTIAL, + WILLNEED = POSIX_MADV_WILLNEED, +} + +when ODIN_OS == .NetBSD { + @(private) LMSYNC :: "__msync13" +} else { + @(private) LMSYNC :: "msync" +} + +when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + PROT_EXEC :: 0x04 + _PROT_NONE :: 0x00 + PROT_READ :: 0x01 + PROT_WRITE :: 0x02 + + MAP_FIXED :: 0x0010 + MAP_PRIVATE :: 0x0002 + MAP_SHARED :: 0x0001 + + when ODIN_OS == .Darwin { + MS_INVALIDATE :: 0x0002 + _MS_SYNC :: 0x0010 + } else when ODIN_OS == .NetBSD { + MS_INVALIDATE :: 0x0002 + _MS_SYNC :: 0x0004 + } else when ODIN_OS == .OpenBSD { + MS_INVALIDATE :: 0x0004 + _MS_SYNC :: 0x0002 + } + MS_ASYNC :: 0x0001 + MS_SYNC :: Sync_Flags{Sync_Flags_Bits(log2(_MS_SYNC))} + + MCL_CURRENT :: 0x0001 + MCL_FUTURE :: 0x0002 + + MAP_FAILED :: rawptr(~uintptr(0)) + + POSIX_MADV_DONTNEED :: 4 + POSIX_MADV_NORMAL :: 0 + POSIX_MADV_RANDOM :: 1 + POSIX_MADV_SEQUENTIAL :: 2 + POSIX_MADV_WILLNEED :: 3 + +} else when ODIN_OS == .FreeBSD { + + PROT_EXEC :: 0x04 + _PROT_NONE :: 0x00 + PROT_READ :: 0x01 + PROT_WRITE :: 0x02 + + MAP_FIXED :: 0x0010 + MAP_PRIVATE :: 0x0002 + MAP_SHARED :: 0x0001 + + MS_ASYNC :: 0x0001 + MS_INVALIDATE :: 0x0002 + MS_SYNC :: Sync_Flags{} + + MCL_CURRENT :: 0x0001 + MCL_FUTURE :: 0x0002 + + MAP_FAILED :: rawptr(~uintptr(0)) + + POSIX_MADV_DONTNEED :: 4 + POSIX_MADV_NORMAL :: 0 + POSIX_MADV_RANDOM :: 1 + POSIX_MADV_SEQUENTIAL :: 2 + POSIX_MADV_WILLNEED :: 3 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_msg.odin b/core/sys/posix/sys_msg.odin new file mode 100644 index 000000000..a8b86e501 --- /dev/null +++ b/core/sys/posix/sys_msg.odin @@ -0,0 +1,161 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/msg.h = XSI message queue structures + +foreign lib { + /* + Provides various operation as specified by the given cmd. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/msgctl.html ]] + */ + @(link_name=LMSGCTL) + msgctl :: proc(msqid: FD, cmd: IPC_Cmd, buf: ^msqid_ds) -> result --- + + /* + Returns the message queue identifier associated with the argument key. + + Returns: -1 (setting errno) on failure, the identifier otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/msgget.html ]] + */ + msgget :: proc(key: key_t, msgflg: IPC_Flags) -> FD --- + + /* + Read a message from the queue. + + Returns: -1 (setting errno) on failure, the bytes received otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/msgrcv.html ]] + */ + msgrcv :: proc( + msgid: FD, + msgp: rawptr, + msgsz: c.size_t, + msgtyp: c.long, + msgflg: IPC_Flags, + ) -> c.ssize_t --- + + /* + Send a message on the queue. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/msgsnd.html ]] + */ + msgsnd :: proc(msgid: FD, msgp: rawptr, msgsz: c.size_t, msgflg: IPC_Flags) -> result --- +} + +when ODIN_OS == .NetBSD { + @(private) LMSGCTL :: "__msgctl50" +} else { + @(private) LMSGCTL :: "msgctl" +} + +when ODIN_OS == .Darwin { + + msgqnum_t :: distinct c.ulong + msglen_t :: distinct c.ulong + + MSG_NOERROR :: 0o10000 + + // NOTE: this is #pragma pack(4) + + msqid_ds :: struct #align(4) { + msg_perm: ipc_perm, /* [PSX] operation permission structure */ + msg_first: c.int32_t, + msg_last: c.int32_t, + msg_cbytes: msglen_t, + msg_qnum: msgqnum_t, /* [PSX] number of messages currently on queue */ + msg_qbytes: msglen_t, /* [PSX] maximum number of bytes allowed on queue */ + msg_lspid: pid_t, /* [PSX] process ID of last msgsnd() */ + msg_lrpid: pid_t, /* [PSX] process ID of last msgrcv() */ + msg_stime: time_t, /* [PSX] time of last msgsnd() */ + msg_pad1: c.int32_t, + using _: struct #align(4) { + msg_rtime: time_t, /* [PSX] time of last msgrcv() */ + msg_pad2: c.int32_t, + using _: struct #align(4) { + msg_ctime: time_t, /* [PSX] time of last change */ + msg_pad3: c.int32_t, + msg_pad4: [4]c.int32_t, + }, + }, + } + +} else when ODIN_OS == .FreeBSD { + + msgqnum_t :: distinct c.ulong + msglen_t :: distinct c.ulong + + MSG_NOERROR :: 0o10000 + + msqid_ds :: struct { + msg_perm: ipc_perm, /* [PSX] operation permission structure */ + __msg_first: rawptr, + __msg_last: rawptr, + msg_cbytes: msglen_t, + msg_qnum: msgqnum_t, /* [PSX] number of messages currently on queue */ + msg_qbytes: msglen_t, /* [PSX] maximum number of bytes allowed on queue */ + msg_lspid: pid_t, /* [PSX] process ID of last msgsnd() */ + msg_lrpid: pid_t, /* [PSX] process ID of last msgrcv() */ + msg_stime: time_t, /* [PSX] time of last msgsnd() */ + msg_rtime: time_t, /* [PSX] time of last msgrcv() */ + msg_ctime: time_t, /* [PSX] time of last change */ + } + +} else when ODIN_OS == .NetBSD { + + msgqnum_t :: distinct c.ulong + msglen_t :: distinct c.size_t + + MSG_NOERROR :: 0o10000 + + msqid_ds :: struct { + msg_perm: ipc_perm, /* [PSX] operation permission structure */ + msg_qnum: msgqnum_t, /* [PSX] number of messages currently on queue */ + msg_qbytes: msglen_t, /* [PSX] maximum number of bytes allowed on queue */ + msg_lspid: pid_t, /* [PSX] process ID of last msgsnd() */ + msg_lrpid: pid_t, /* [PSX] process ID of last msgrcv() */ + msg_stime: time_t, /* [PSX] time of last msgsnd() */ + msg_rtime: time_t, /* [PSX] time of last msgrcv() */ + msg_ctime: time_t, /* [PSX] time of last change */ + + _msg_first: rawptr, + _msg_last: rawptr, + _msg_cbytes: msglen_t, + } + +} else when ODIN_OS == .OpenBSD { + + msgqnum_t :: distinct c.ulong + msglen_t :: distinct c.ulong + + MSG_NOERROR :: 0o10000 + + msqid_ds :: struct { + msg_perm: ipc_perm, /* [PSX] operation permission structure */ + __msg_first: rawptr, + __msg_last: rawptr, + msg_cbytes: msglen_t, + msg_qnum: msgqnum_t, /* [PSX] number of messages currently on queue */ + msg_qbytes: msglen_t, /* [PSX] maximum number of bytes allowed on queue */ + msg_lspid: pid_t, /* [PSX] process ID of last msgsnd() */ + msg_lrpid: pid_t, /* [PSX] process ID of last msgrcv() */ + msg_stime: time_t, /* [PSX] time of last msgsnd() */ + msg_pad1: c.long, + msg_rtime: time_t, /* [PSX] time of last msgrcv() */ + msg_pad2: c.long, + msg_ctime: time_t, /* [PSX] time of last change */ + msg_pad3: c.long, + msg_pad4: [4]c.long, + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_resource.odin b/core/sys/posix/sys_resource.odin new file mode 100644 index 000000000..6716d60c3 --- /dev/null +++ b/core/sys/posix/sys_resource.odin @@ -0,0 +1,152 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/resource.h - definitions XSI resource operations + +foreign lib { + /* + Gets the nice value of the process, process group or user given. + + Note that a nice value can be -1, so checking for an error would mean clearing errno, doing the + call and then checking that this returns -1 and it has an errno. + + Returns: -1 (setting errno) on failure, the value otherwise + + Example: + pid := posix.getpid() + posix.set_errno(.NONE) + prio := posix.getpriority(.PROCESS, pid) + if err := posix.errno(); prio == -1 && err != .NONE { + // Handle error... + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpriority.html ]] + */ + getpriority :: proc(which: Which_Prio, who: id_t) -> c.int --- + + /* + Sets the nice value of the process, process group or user given. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpriority.html ]] + */ + setpriority :: proc(which: Which_Prio, who: id_t, value: c.int) -> result --- + + /* + Get a resource limit. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html ]] + */ + getrlimit :: proc(resource: Resource, rlp: ^rlimit) -> result --- + + /* + Set a resource limit. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrlimit.html ]] + */ + setrlimit :: proc(resource: Resource, rlp: ^rlimit) -> result --- + + /* + Get resource usage. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getrusage.html ]] + */ + @(link_name=LGETRUSAGE) + getrusage :: proc(who: Which_Usage, rusage: ^rusage) -> result --- +} + +Which_Prio :: enum c.int { + PROCESS = PRIO_PROCESS, + PGRP = PRIO_PGRP, + USER = PRIO_USER, +} + +Which_Usage :: enum c.int { + SELF = RUSAGE_SELF, + CHILDREN = RUSAGE_CHILDREN, +} + +Resource :: enum c.int { + // Maximum byte size of a core file that may be created by a process. + CORE = RLIMIT_CORE, + // Maximum amount of CPU time, in seconds, used by a process. + CPU = RLIMIT_CPU, + // Maximum size of data segment of the process, in bytes. + DATA = RLIMIT_DATA, + // Maximum size of a file, in bytes, that may be created by a process. + FSIZE = RLIMIT_FSIZE, + // A number one greater than the maximum value that the system may assign to a newly-created descriptor. + NOFILE = RLIMIT_NOFILE, + // The maximum size of the initial thread's stack, in bytes. + STACK = RLIMIT_STACK, + // Maximum size of total available memory of the process, in bytes. + AS = RLIMIT_AS, +} + +when ODIN_OS == .NetBSD { + @(private) LGETRUSAGE :: "__getrusage50" +} else { + @(private) LGETRUSAGE :: "getrusage" +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + PRIO_PROCESS :: 0 + PRIO_PGRP :: 1 + PRIO_USER :: 2 + + rlim_t :: distinct c.uint64_t + + RLIM_INFINITY :: (rlim_t(1) << 63) - 1 + RLIM_SAVED_MAX :: RLIM_INFINITY + RLIM_SAVED_CUR :: RLIM_INFINITY + + RUSAGE_SELF :: 0 + RUSAGE_CHILDREN :: -1 + + rlimit :: struct { + rlim_cur: rlim_t, /* [PSX] the current (soft) limit */ + rlim_max: rlim_t, /* [PSX] the hard limit */ + } + + rusage :: struct { + ru_utime: timeval, /* [PSX] user time used */ + ru_stime: timeval, /* [PSX] system time used */ + + // Informational aliases for source compatibility with programs + // that need more information than that provided by standards, + // and which do not mind being OS-dependent. + + ru_maxrss: c.long, /* max resident set size (PL) */ + ru_ixrss: c.long, /* integral shared memory size (NU) */ + ru_idrss: c.long, /* integral unshared data (NU) */ + ru_isrss: c.long, /* integral unshared stack (NU) */ + ru_minflt: c.long, /* page reclaims (NU) */ + ru_majflt: c.long, /* page faults (NU) */ + ru_nswap: c.long, /* swaps (NU) */ + ru_inblock: c.long, /* block input operations (atomic) */ + ru_outblock: c.long, /* block output operations (atomic) */ + ru_msgsnd: c.long, /* messages sent (atomic) */ + ru_msgrcv: c.long, /* messages received (atomic) */ + ru_nsignals: c.long, /* signals received (atomic) */ + ru_nvcsw: c.long, /* voluntary context switches (atomic) */ + ru_nivcsw: c.long, /* involuntary " */ + } + + RLIMIT_CORE :: 4 + RLIMIT_CPU :: 0 + RLIMIT_DATA :: 2 + RLIMIT_FSIZE :: 1 + RLIMIT_NOFILE :: 8 + RLIMIT_STACK :: 3 + RLIMIT_AS :: 5 when ODIN_OS == .Darwin || ODIN_OS == .OpenBSD else 10 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_select.odin b/core/sys/posix/sys_select.odin new file mode 100644 index 000000000..3392e02bc --- /dev/null +++ b/core/sys/posix/sys_select.odin @@ -0,0 +1,120 @@ +package posix + +import "base:intrinsics" + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/select.h - select types + +foreign lib { + /* + Examines the file descriptor sets to see whether some of their descriptors are ready for writing, + or have an exceptional condition pending, respectively. + + Returns: -1 (setting errno) on failure, total amount of bits set in the bit masks otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html ]] + */ + @(link_name=LPSELECT) + pselect :: proc( + nfds: c.int, + readfds: ^fd_set, + writefds: ^fd_set, + errorfds: ^fd_set, + timeout: ^timespec, + sigmask: ^sigset_t, + ) -> c.int --- + + /* + Equivalent to pselect() except a more specific timeout resolution (nanoseconds), + does not have a signal mask, and may modify the timeout. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html ]] + */ + @(link_name=LSELECT) + select :: proc( + nfds: c.int, + readfds: ^fd_set, + writefds: ^fd_set, + errorfds: ^fd_set, + timeout: ^timeval, + ) -> c.int --- +} + +when ODIN_OS == .NetBSD { + LPSELECT :: "__pselect50" + LSELECT :: "__select50" +} else { + LPSELECT :: "pselect" + LSELECT :: "select" +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + suseconds_t :: distinct (c.int32_t when ODIN_OS == .Darwin || ODIN_OS == .NetBSD else c.long) + + timeval :: struct { + tv_sec: time_t, /* [PSX] seconds */ + tv_usec: suseconds_t, /* [PSX] microseconds */ + } + + // Maximum number of file descriptors in the fd_set structure. + FD_SETSIZE :: #config(POSIX_FD_SETSIZE, 256 when ODIN_OS == .NetBSD else 1024) + + @(private) + __NFDBITS :: size_of(c.int32_t) * 8 + + // NOTE: this seems correct for FreeBSD but they do use a set backed by the long type themselves (thus the align change). + @(private) + ALIGN :: align_of(c.long) when ODIN_OS == .FreeBSD else align_of(c.int32_t) + + fd_set :: struct #align(ALIGN) { + fds_bits: [(FD_SETSIZE / __NFDBITS) when (FD_SETSIZE % __NFDBITS) == 0 else (FD_SETSIZE / __NFDBITS) + 1]c.int32_t, + } + + @(private) + __check_fd_set :: #force_inline proc "contextless" (_a: FD, _b: rawptr) -> bool { + if _a < 0 { + set_errno(.EINVAL) + } + + if _a >= FD_SETSIZE { + set_errno(.EINVAL) + } + + return true + } + + FD_CLR :: #force_inline proc "contextless" (_fd: FD, _p: ^fd_set) { + if __check_fd_set(_fd, _p) { + _p.fds_bits[cast(c.ulong)_fd / __NFDBITS] &= ~cast(c.int32_t)((cast(c.ulong)1) << (cast(c.ulong)_fd % __NFDBITS)) + } + } + + FD_ISSET :: #force_inline proc "contextless" (_fd: FD, _p: ^fd_set) -> bool { + if __check_fd_set(_fd, _p) { + return bool(_p.fds_bits[cast(c.ulong)_fd / __NFDBITS] & cast(c.int32_t)((cast(c.ulong)1) << (cast(c.ulong)_fd % __NFDBITS))) + } + + return false + } + + FD_SET :: #force_inline proc "contextless" (_fd: FD, _p: ^fd_set) { + if __check_fd_set(_fd, _p) { + _p.fds_bits[cast(c.ulong)_fd / __NFDBITS] |= cast(c.int32_t)((cast(c.ulong)1) << (cast(c.ulong)_fd % __NFDBITS)) + } + } + + FD_ZERO :: #force_inline proc "contextless" (_p: ^fd_set) { + intrinsics.mem_zero(_p, size_of(fd_set)) + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_sem.odin b/core/sys/posix/sys_sem.odin new file mode 100644 index 000000000..3fcde325b --- /dev/null +++ b/core/sys/posix/sys_sem.odin @@ -0,0 +1,132 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/sem.h - XSI semaphore facility + +foreign lib { + /* + Provides various semaphore control operation as specified by cmd. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/semctl.html ]] + */ + @(link_name=LSEMCTL) + semctl :: proc(semid: FD, semnum: c.int, cmd: Sem_Cmd, arg: ^semun = nil) -> c.int --- + + /* + Returns the semaphore identifier associated with key. + + Returns: -1 (setting errno) on failure, a semaphore file descriptor otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/semget.html ]] + */ + semget :: proc(key: key_t, nsems: c.int, semflg: IPC_Flags) -> FD --- + + /* + Perform atomically a user-defined array of semaphore operations in array order on the set of + semaphores associated with the semaphore identifier specified by the argument semid. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/semop.html ]] + */ + semop :: proc(semid: FD, sops: [^]sembuf, nsops: c.size_t) -> result --- +} + +Sem_Cmd :: enum c.int { + // Returns the value of semncnt. + GETNCNT = GETNCNT, + // Returns the value of sempid. + GETPID = GETPID, + // Return the value of semval. + GETVAL = GETVAL, + // Returns the value of semval for each semaphore in the semaphore set. + GETALL = GETALL, + // Returns the value of semzcnt. + GETZCNT = GETZCNT, + // Sets the value of semval to arg.val. + SETVAL = SETVAL, + // Sets the value of semval for each semaphore in the set. + SETALL = SETALL, +} + +semun :: struct #raw_union { + val: c.int, + buf: ^semid_ds, + array: [^]c.ushort, +} + +when ODIN_OS == .NetBSD { + @(private) LSEMCTL :: "__semctl50" +} else { + @(private) LSEMCTL :: "semctl" +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + SEM_UNDO :: 0o10000 + + GETNCNT :: 3 + GETPID :: 4 + GETVAL :: 5 + GETALL :: 6 + GETZCNT :: 7 + SETVAL :: 8 + SETALL :: 9 + + when ODIN_OS == .Darwin { + // NOTE: this is #pragma pack(4) + + semid_ds :: struct #align(4) { + sem_perm: ipc_perm, /* [PSX] operation permission structure */ + sem_base: c.int32_t, /* 32 bit base ptr for semaphore set */ + sem_nsems: c.ushort, /* [PSX] number of semaphores in set */ + sem_otime: time_t, /* [PSX] last semop() */ + sem_pad1: c.int32_t, + using _: struct #align(4) { + sem_ctime: time_t, /* [PSX] last time changed by semctl() */ + sem_pad2: c.int32_t, + sem_pad3: [4]c.int32_t, + }, + } + } else when ODIN_OS == .FreeBSD { + semid_ds :: struct { + sem_perm: ipc_perm, /* [PSX] operation permission structure */ + sem_base: rawptr, /* 32 bit base ptr for semaphore set */ + sem_nsems: c.ushort, /* [PSX] number of semaphores in set */ + sem_otime: time_t, /* [PSX] last semop() */ + sem_ctime: time_t, /* [PSX] last time changed by semctl() */ + } + } else when ODIN_OS == .NetBSD { + semid_ds :: struct { + sem_perm: ipc_perm, /* [PSX] operation permission structure */ + sem_nsems: c.ushort, /* [PSX] number of semaphores in set */ + sem_otime: time_t, /* [PSX] last semop() */ + sem_ctime: time_t, /* [PSX] last time changed by semctl() */ + _sem_base: rawptr, /* 32 bit base ptr for semaphore set */ + } + } else when ODIN_OS == .OpenBSD { + semid_ds :: struct { + sem_perm: ipc_perm, /* [PSX] operation permission structure */ + sem_nsems: c.ushort, /* [PSX] number of semaphores in set */ + sem_otime: time_t, /* [PSX] last semop() */ + sem_pad1: c.long, + sem_ctime: time_t, /* [PSX] last time changed by semctl() */ + sem_pad2: c.long, + sem_pad3: [4]c.long, + } + } + + sembuf :: struct { + sem_num: c.ushort, /* [PSX] semaphore number */ + sem_op: c.short, /* [PSX] semaphore operation */ + sem_flg: c.short, /* [PSX] operation flags */ + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_shm.odin b/core/sys/posix/sys_shm.odin new file mode 100644 index 000000000..3bc883ce4 --- /dev/null +++ b/core/sys/posix/sys_shm.odin @@ -0,0 +1,146 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/shm.h = XSI shared memory facility + +foreign lib { + /* + Attaches the shared memory segment associated with the identifier + into the address space of the calling process. + + Returns: nil (setting errno) on failure, the address otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shmat.html ]] + */ + shmat :: proc(shmid: FD, shmaddr: rawptr, shmflag: SHM_Flags) -> rawptr --- + + /* + Provides various shared memory operation as specified by the given cmd. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shmctl.html ]] + */ + @(link_name=LSHMCTL) + shmctl :: proc(shmid: FD, cmd: IPC_Cmd, buf: ^shmid_ds) -> result --- + + /* + Detaches the shared memory segment located at the address specified. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shmdt.html ]] + */ + shmdt :: proc(shmaddr: rawptr) -> result --- + + /* + Returns the shared memory identifier associated with key. + + Returns: -1 (setting errno) on failure, the shared memory ID otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shmget.html ]] + */ + shmget :: proc(key: key_t, size: c.size_t, shmflag: SHM_Flags) -> FD --- +} + +SHM_Flag_Bits :: enum c.int { + RDONLY = log2(SHM_RDONLY), + RND = log2(SHM_RND), +} +SHM_Flags :: bit_set[SHM_Flag_Bits; c.int] + +when ODIN_OS == .NetBSD { + @(private) LSHMCTL :: "__shmctl50" +} else { + @(private) LSHMCTL :: "shmctl" +} + +when ODIN_OS == .Darwin { + + SHM_RDONLY :: 0o10000 + SHM_RND :: 0o20000 + + SHMLBA :: 16 * 1024 when ODIN_ARCH == .arm64 else 4096 + + shmatt_t :: distinct c.ushort + + // NOTE: this is #pragma pack(4) + + shmid_ds :: struct #align(4) { + shm_perm: ipc_perm, /* [PSX] operation permission structure */ + shm_segsz: c.size_t, /* [PSX] size of segment in bytes */ + shm_lpid: pid_t, /* [PSX] process ID of last shared memory operation */ + shm_cpid: pid_t, /* [PSX] process ID of creator */ + shm_nattch: shmatt_t, /* [PSX] number of current attaches */ + using _: struct #align(4) { + shm_atime: time_t, /* [PSX] time of last shmat() */ + shm_dtime: time_t, /* [PSX] time of last shmdt() */ + shm_ctime: time_t, /* [PSX] time of last change by shmctl() */ + shm_internal: rawptr, + }, + } + +} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD { + + SHM_RDONLY :: 0o10000 + SHM_RND :: 0o20000 + + SHMLBA :: PAGESIZE + + shmatt_t :: distinct c.uint + + when ODIN_OS == .FreeBSD { + shmid_ds :: struct { + shm_perm: ipc_perm, /* [PSX] operation permission structure */ + shm_segsz: c.size_t, /* [PSX] size of segment in bytes */ + shm_lpid: pid_t, /* [PSX] process ID of last shared memory operation */ + shm_cpid: pid_t, /* [PSX] process ID of creator */ + shm_nattch: shmatt_t, /* [PSX] number of current attaches */ + shm_atime: time_t, /* [PSX] time of last shmat() */ + shm_dtime: time_t, /* [PSX] time of last shmdt() */ + shm_ctime: time_t, /* [PSX] time of last change by shmctl() */ + } + } else { + shmid_ds :: struct { + shm_perm: ipc_perm, /* [PSX] operation permission structure */ + shm_segsz: c.size_t, /* [PSX] size of segment in bytes */ + shm_lpid: pid_t, /* [PSX] process ID of last shared memory operation */ + shm_cpid: pid_t, /* [PSX] process ID of creator */ + shm_nattch: shmatt_t, /* [PSX] number of current attaches */ + shm_atime: time_t, /* [PSX] time of last shmat() */ + shm_dtime: time_t, /* [PSX] time of last shmdt() */ + shm_ctime: time_t, /* [PSX] time of last change by shmctl() */ + _shm_internal: rawptr, + } + } + +} else when ODIN_OS == .OpenBSD { + + SHM_RDONLY :: 0o10000 + SHM_RND :: 0o20000 + + SHMLBA :: 1 << 12 + + shmatt_t :: distinct c.short + + shmid_ds :: struct { + shm_perm: ipc_perm, /* [PSX] operation permission structure */ + shm_segsz: c.int, /* [PSX] size of segment in bytes */ + shm_lpid: pid_t, /* [PSX] process ID of last shared memory operation */ + shm_cpid: pid_t, /* [PSX] process ID of creator */ + shm_nattch: shmatt_t, /* [PSX] number of current attaches */ + shm_atime: time_t, /* [PSX] time of last shmat() */ + __shm_atimensec: c.long, + shm_dtime: time_t, /* [PSX] time of last shmdt() */ + __shm_dtimensec: c.long, + shm_ctime: time_t, /* [PSX] time of last change by shmctl() */ + __shm_ctimensec: c.long, + _shm_internal: rawptr, + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_socket.odin b/core/sys/posix/sys_socket.odin new file mode 100644 index 000000000..e82101367 --- /dev/null +++ b/core/sys/posix/sys_socket.odin @@ -0,0 +1,491 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import libc "system:System.framework" +} else { + foreign import libc "system:c" +} + +// sys/socket.h - main sockets header + +#assert(Protocol.IP == Protocol(0), "socket() assumes this") + +foreign libc { + /* + Creates a socket. + + Returns: -1 (setting errno) on failure, file descriptor of socket otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html ]] + */ + @(link_name=LSOCKET) + socket :: proc(domain: AF, type: Sock, protocol: Protocol = .IP) -> FD --- + + /* + Extracts the first connection on the queue of pending connections. + + Blocks (if not O_NONBLOCK) if there is no pending connection. + + Returns: -1 (setting errno) on failure, file descriptor of accepted socket otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html ]] + */ + accept :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> FD --- + + /* + Assigns a local socket address to the socket. + + Example: + sfd := posix.socket(.UNIX, .STREAM) + if sfd == -1 { + /* Handle error */ + } + + addr: posix.sockaddr_un + addr.sun_family = .UNIX + copy(addr.sun_path[:], "/somepath\x00") + + if posix.bind(sfd, (^posix.sockaddr)(&addr), size_of(addr)) != .OK { + /* Handle error */ + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html ]] + */ + bind :: proc(socket: FD, address: ^sockaddr, address_len: socklen_t) -> result --- + + /* + Attempt to make a connection. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html ]] + */ + connect :: proc(socket: FD, address: ^sockaddr, address_len: socklen_t) -> result --- + + /* + Get the peer address of the specified socket. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html ]] + */ + getpeername :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> result --- + + /* + Get the socket name. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html ]] + */ + getsockname :: proc(socket: FD, address: ^sockaddr, address_len: ^socklen_t) -> result --- + + /* + Retrieves the value for the option specified by option_name. + + level: either `c.int(posix.Protocol(...))` to specify a protocol level or `posix.SOL_SOCKET` + to specify the socket local level. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html ]] + */ + getsockopt :: proc( + socket: FD, + level: c.int, + option_name: Sock_Option, + option_value: rawptr, + option_len: ^socklen_t, + ) -> result --- + + /* + Sets the specified option. + + level: either `c.int(posix.Protocol(...))` to specify a protocol level or `posix.SOL_SOCKET` + to specify the socket local level. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html ]] + */ + setsockopt :: proc( + socket: FD, + level: c.int, + option_name: Sock_Option, + option_value: rawptr, + option_len: socklen_t, + ) -> result --- + + /* + Mark the socket as a socket accepting connections. + + backlog provides a hint to limit the number of connections on the listen queue. + Implementation may silently reduce the backlog, additionally `SOMAXCONN` specifies the maximum + an implementation has to support. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html ]] + */ + listen :: proc(socket: FD, backlog: c.int) -> result --- + + /* + Receives a message from a socket. + + Blocks (besides with O_NONBLOCK) if there is nothing to receive. + + Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html ]] + */ + recv :: proc(socket: FD, buffer: rawptr, length: c.size_t, flags: Msg_Flags) -> c.ssize_t --- + + /* + Receives a message from a socket. + + Equivalent to recv() but retrieves the source address too. + + Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html ]] + */ + recvfrom :: proc( + socket: FD, + buffer: rawptr, + length: c.size_t, + flags: Msg_Flags, + address: ^sockaddr, + address_len: ^socklen_t, + ) -> c.ssize_t --- + + /* + Receives a message from a socket. + + Returns: 0 when the peer shutdown with no more messages, -1 (setting errno) on failure, the amount of bytes received on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html ]] + */ + recvmsg :: proc(socket: FD, message: ^msghdr, flags: Msg_Flags) -> c.ssize_t --- + + /* + Sends a message on a socket. + + Returns: -1 (setting errno) on failure, the amount of bytes received on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html ]] + */ + send :: proc(socket: FD, buffer: rawptr, length: c.size_t, flags: Msg_Flags) -> c.ssize_t --- + + /* + Sends a message on a socket. + + Returns: -1 (setting errno) on failure, the amount of bytes received on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendmsg.html ]] + */ + sendmsg :: proc(socket: FD, message: ^msghdr, flags: Msg_Flags) -> c.ssize_t --- + + /* + Sends a message on a socket. + + If the socket is connectionless, the dest_addr is used to send to. + + Returns: -1 (setting errno) on failure, the amount of bytes received on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html ]] + */ + sendto :: proc( + socket: FD, + message: rawptr, + length: c.size_t, + flags: Msg_Flags, + dest_addr: ^sockaddr, + dest_len: socklen_t, + ) -> c.ssize_t --- + + /* + Shuts down a socket end or both. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html ]] + */ + shutdown :: proc(socket: FD, how: Shut) -> result --- + + /* + Determine wheter a socket is at the out-of-band mark. + + Returns: -1 (setting errno) on failure, 0 if not at the mark, 1 if it is + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sockatmark.html ]] + */ + sockatmark :: proc(socket: FD) -> c.int --- + + /* + Create a pair of connected sockets. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html ]] + */ + socketpair :: proc(domain: AF, type: Sock, protocol: Protocol, socket_vector: ^[2]FD) -> result --- +} + +AF_UNSPEC :: 0 + +AF :: enum c.int { + // Unspecified. + UNSPEC = AF_UNSPEC, + // Internet domain sockets for use with IPv4 addresses. + INET = AF_INET, + // Internet domain sockets for use with IPv6 addresses. + INET6 = AF_INET6, + // UNIX domain sockets. + UNIX = AF_UNIX, +} + +sa_family_t :: enum _sa_family_t { + // Unspecified. + UNSPEC = AF_UNSPEC, + // Internet domain sockets for use with IPv4 addresses. + INET = AF_INET, + // Internet domain sockets for use with IPv6 addresses. + INET6 = AF_INET6, + // UNIX domain sockets. + UNIX = AF_UNIX, +} + +Sock :: enum c.int { + // Datagram socket. + DGRAM = SOCK_DGRAM, + // Raw Protocol Interface. + RAW = SOCK_RAW, + // Sequenced-packet socket. + SEQPACKET = SOCK_SEQPACKET, + // Byte-stream socket. + STREAM = SOCK_STREAM, +} + +Shut :: enum c.int { + // Disables further receive operations. + RD = SHUT_RD, + // Disables further send and receive operations. + RDWR = SHUT_RDWR, + // Disables further send operations. + WR = SHUT_WR, +} + +Msg_Flag_Bits :: enum c.int { + // Control data truncated. + CTRUNC = log2(MSG_CTRUNC), + // Send without using routing table. + DONTROUTE = log2(MSG_DONTROUTE), + // Terminates a record (if supported by protocol). + EOR = log2(MSG_EOR), + // Out-of-band data. + OOB = log2(MSG_OOB), + // No SIGPIPE is generated when an attempt to send is made on a stream-oriented socket that is + // no longer connected. + NOSIGNAL = log2(MSG_NOSIGNAL), + // Leave received data in queue. + PEEK = log2(MSG_PEEK), + // Normal data truncated. + TRUNC = log2(MSG_TRUNC), + // Attempt to fill the read buffer. + WAITALL = log2(MSG_WAITALL), +} +Msg_Flags :: bit_set[Msg_Flag_Bits; c.int] + +Sock_Option :: enum c.int { + // Transmission of broadcast message is supported. + BROADCAST = SO_BROADCAST, + // Debugging information is being recorded. + DEBUG = SO_DEBUG, + // Bypass normal routing. + DONTROUTE = SO_DONTROUTE, + // Socket error status. + ERROR = SO_ERROR, + // Connections are kept alive with periodic messages. + KEEPALIVE = SO_KEEPALIVE, + // Socket lingers on close. + LINGER = SO_LINGER, + // Out-of-band data is transmitted in line. + OOBINLINE = SO_OOBINLINE, + // Receive buffer size. + RCVBUF = SO_RCVBUF, + // Receive low water mark. + RCVLOWAT = SO_RCVLOWAT, + // Receive timeout. + RCVTIMEO = SO_RCVTIMEO, + // Reuse of local addresses is supported. + REUSEADDR = SO_REUSEADDR, + // Send buffer size. + SNDBUF = SO_SNDBUF, + // Send low water mark. + SNDLOWAT = SO_SNDLOWAT, + // Send timeout. + SNDTIMEO = SO_SNDTIMEO, + // Socket type. + TYPE = SO_TYPE, +} + +when ODIN_OS == .NetBSD { + @(private) LSOCKET :: "__socket30" +} else { + @(private) LSOCKET :: "socket" +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + socklen_t :: distinct c.uint + + _sa_family_t :: distinct c.uint8_t + + sockaddr :: struct { + sa_len: c.uint8_t, /* total length */ + sa_family: sa_family_t, /* [PSX] address family */ + sa_data: [14]c.char, /* [PSX] socket address */ + } + + + when ODIN_OS == .OpenBSD { + @(private) + _SS_PAD1SIZE :: 6 + @(private) + _SS_PAD2SIZE :: 240 + } else { + @(private) + _SS_MAXSIZE :: 128 + @(private) + _SS_ALIGNSIZE :: size_of(c.int64_t) + @(private) + _SS_PAD1SIZE :: _SS_ALIGNSIZE - size_of(c.uint8_t) - size_of(sa_family_t) + @(private) + _SS_PAD2SIZE :: _SS_MAXSIZE - size_of(c.uint8_t) - size_of(sa_family_t) - _SS_PAD1SIZE - _SS_ALIGNSIZE + } + + sockaddr_storage :: struct { + ss_len: c.uint8_t, /* address length */ + ss_family: sa_family_t, /* [PSX] address family */ + __ss_pad1: [_SS_PAD1SIZE]c.char, + __ss_align: c.int64_t, /* force structure storage alignment */ + __ss_pad2: [_SS_PAD2SIZE]c.char, + } + + msghdr :: struct { + msg_name: rawptr, /* [PSX] optional address */ + msg_namelen: socklen_t, /* [PSX] size of address */ + msg_iov: [^]iovec, /* [PSX] scatter/gather array */ + msg_iovlen: c.int, /* [PSX] members in msg_iov */ + msg_control: rawptr, /* [PSX] ancillary data */ + msg_controllen: socklen_t, /* [PSX] ancillary data buffer length */ + msg_flags: Msg_Flags, /* [PSX] flags on received message */ + } + + cmsghdr :: struct { + cmsg_len: socklen_t, /* [PSX] data byte count, including cmsghdr */ + cmsg_level: c.int, /* [PSX] originating protocol */ + cmsg_type: c.int, /* [PSX] protocol-specific type */ + } + + SCM_RIGHTS :: 0x01 + + @(private) + __ALIGN32 :: #force_inline proc "contextless" (p: uintptr) -> uintptr { + __ALIGNBYTES32 :: size_of(c.uint32_t) - 1 + return (p + __ALIGNBYTES32) &~ __ALIGNBYTES32 + } + + // Returns a pointer to the data array. + CMSG_DATA :: #force_inline proc "contextless" (cmsg: ^cmsghdr) -> [^]c.uchar { + return ([^]c.uchar)(uintptr(cmsg) + __ALIGN32(size_of(cmsghdr))) + } + + // Returns a pointer to the next cmsghdr or nil. + CMSG_NXTHDR :: #force_inline proc "contextless" (mhdr: ^msghdr, cmsg: ^cmsghdr) -> ^cmsghdr { + if cmsg == nil { + return CMSG_FIRSTHDR(mhdr) + } + + ptr := uintptr(cmsg) + __ALIGN32(uintptr(cmsg.cmsg_len)) + if ptr + __ALIGN32(size_of(cmsghdr)) > uintptr(mhdr.msg_control) + uintptr(mhdr.msg_controllen) { + return nil + } + + return (^cmsghdr)(ptr) + } + + // Returns a pointer to the first cmsghdr or nil. + CMSG_FIRSTHDR :: #force_inline proc "contextless" (mhdr: ^msghdr) -> ^cmsghdr { + if mhdr.msg_controllen >= size_of(cmsghdr) { + return (^cmsghdr)(mhdr.msg_control) + } + + return nil + } + + linger :: struct { + l_onoff: c.int, /* [PSX] indicates whether linger option is enabled */ + l_linger: c.int, /* [PSX] linger time in seconds */ + } + + SOCK_DGRAM :: 2 + SOCK_RAW :: 3 + SOCK_SEQPACKET :: 5 + SOCK_STREAM :: 1 + + // Options to be accessed at socket level, not protocol level. + SOL_SOCKET :: 0xffff + + SO_ACCEPTCONN :: 0x0002 + SO_BROADCAST :: 0x0020 + SO_DEBUG :: 0x0001 + SO_DONTROUTE :: 0x0010 + SO_ERROR :: 0x1007 + SO_KEEPALIVE :: 0x0008 + SO_OOBINLINE :: 0x0100 + SO_RCVBUF :: 0x1002 + SO_RCVLOWAT :: 0x1004 + SO_REUSEADDR :: 0x0004 + SO_SNDBUF :: 0x1001 + SO_SNDLOWAT :: 0x1003 + SO_TYPE :: 0x1008 + + when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD { + SO_LINGER :: 0x1080 + SO_RCVTIMEO :: 0x1006 + SO_SNDTIMEO :: 0x1005 + } else when ODIN_OS == .NetBSD { + SO_LINGER :: 0x0080 + SO_RCVTIMEO :: 0x100c + SO_SNDTIMEO :: 0x100b + } else when ODIN_OS == .OpenBSD { + SO_LINGER :: 0x0080 + SO_RCVTIMEO :: 0x1006 + SO_SNDTIMEO :: 0x1005 + } + + // The maximum backlog queue length for listen(). + SOMAXCONN :: 128 + + MSG_CTRUNC :: 0x20 + MSG_DONTROUTE :: 0x4 + MSG_EOR :: 0x8 + MSG_OOB :: 0x1 + MSG_PEEK :: 0x2 + MSG_TRUNC :: 0x10 + MSG_WAITALL :: 0x40 + + when ODIN_OS == .Darwin { + MSG_NOSIGNAL :: 0x80000 + } else when ODIN_OS == .FreeBSD { + MSG_NOSIGNAL :: 0x00020000 + } else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + MSG_NOSIGNAL :: 0x0400 + } + + AF_INET :: 2 + AF_UNIX :: 1 + + when ODIN_OS == .Darwin { + AF_INET6 :: 30 + } else when ODIN_OS == .FreeBSD { + AF_INET6 :: 28 + } else when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + AF_INET6 :: 24 + } + + SHUT_RD :: 0 + SHUT_RDWR :: 2 + SHUT_WR :: 1 + +} else { + #panic("posix is unimplemented for the current target") +} + diff --git a/core/sys/posix/sys_stat.odin b/core/sys/posix/sys_stat.odin new file mode 100644 index 000000000..016f1b1e6 --- /dev/null +++ b/core/sys/posix/sys_stat.odin @@ -0,0 +1,540 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/stat.h - data returned by the stat() function + +foreign lib { + + /* + Equivalent to either stat or lstat (based on the SYMLINK_NOFOLLOW bit in flags) + but resolves relative paths based on the given fd. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatat.html ]] + */ + @(link_name="fstatat" + INODE_SUFFIX) + fstatat :: proc(fd: FD, path: cstring, buf: ^stat_t, flag: AT_Flags) -> result --- + + /* + Obtain information about a "file" at the given path. + + Follows symbolic links. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatat.html ]] + */ + @(link_name=LSTAT) + stat :: proc(path: cstring, buf: ^stat_t) -> result --- + + /* + Obtain information about an open file. + + Follows symbol links. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstat.html ]] + */ + @(link_name=LFSTAT) + fstat :: proc(fildes: FD, buf: ^stat_t) -> result --- + + /* + Obtain information about a "file" at the given path. + + Does not follow symlinks (will stat the symlink itself). + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatat.html ]] + */ + @(link_name=LLSTAT) + lstat :: proc(path: cstring, buf: ^stat_t) -> result --- + + /* + Change the mode of a file. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html ]] + */ + chmod :: proc(path: cstring, mode: mode_t) -> result --- + + /* + Equivalent to chmod but takes an open file descriptor. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html ]] + */ + fchmod :: proc(fd: FD, mode: mode_t) -> result --- + + /* + Equivalent to chmod but follows (or doesn't) symlinks based on the flag and resolves + relative paths from the given fd. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html ]] + */ + fchmodat :: proc(fd: FD, path: cstring, mode: mode_t, flag: AT_Flags) -> result --- + + /* + Make a directory. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html ]] + */ + mkdir :: proc(path: cstring, mode: mode_t) -> result --- + + /* + Equivalent to mkdir but relative paths are relative to fd. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html ]] + */ + mkdirat :: proc(fd: FD, path: cstring, mode: mode_t) -> result --- + + /* + Make a FIFO special file. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html ]] + */ + mkfifo :: proc(path: cstring, mode: mode_t) -> result --- + + /* + Equivalent to mkfifo but relative paths are relative to fd. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html ]] + */ + mkfifoat :: proc(fd: FD, path: cstring, mode: mode_t) -> result --- + + /* + Make directory, special file, or regular file. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknodat.html ]] + */ + @(link_name=LMKNOD) + mknod :: proc(path: cstring, mode: mode_t, dev: dev_t) -> result --- + + /* + Equivalent to mknod but relative paths are relative to fd. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknodat.html ]] + */ + mknodat :: proc(fd: FD, path: cstring, mode: mode_t, dev: dev_t) -> result --- + + /* + Sets the file access and modification time of the given file descriptor. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html ]] + */ + futimens :: proc(fd: FD, times: ^[2]timespec) -> result --- + + /* + Equivalent to futimens. + Relative directories are based on fd. + Symlinks may or may not be followed based on the flags. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html ]] + */ + utimensat :: proc(fd: FD, path: cstring, times: ^[2]timespec, flag: AT_Flags) -> result --- + + /* + Set and get the file mode creation flags. + + Makes the file mode permissions bits in cmask the new default for the process. + + Returns: the previous value + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/umask.html ]] + */ + umask :: proc(cmask: mode_t) -> mode_t --- +} + +// Read, write, execute user. +S_IRWXU :: mode_t{ .IRUSR, .IWUSR, .IXUSR } +// Read, write, execute group. +S_IRWXG :: mode_t{ .IRGRP, .IWGRP, .IXGRP } +// Read, write, execute other. +S_IRWXO :: mode_t{ .IROTH, .IWOTH, .IXOTH } + +Mode_Bits :: enum c.int { + // File type: + + IFBLK = log2(S_IFBLK), /* Block special */ + IFCHR = log2(S_IFCHR), /* Character special */ + IFIFO = log2(S_IFIFO), /* FIFO special */ + IFREG = log2(S_IFREG), /* Regular */ + IFDIR = log2(S_IFDIR), /* Directory */ + IFLNK = log2(S_IFLNK), /* Symbolic link */ + IFSOCK = log2(S_IFSOCK), /* Socket */ + + // Permissions: + + IRUSR = log2(_S_IRUSR), /* R for owner */ + IWUSR = log2(_S_IWUSR), /* W for owner */ + IXUSR = log2(_S_IXUSR), /* X for owner */ + + IRGRP = log2(_S_IRGRP), /* R for group */ + IWGRP = log2(_S_IWGRP), /* W for group */ + IXGRP = log2(_S_IXGRP), /* X for group */ + + IROTH = log2(_S_IROTH), /* R for other */ + IWOTH = log2(_S_IWOTH), /* W for other */ + IXOTH = log2(_S_IXOTH), /* X for other */ + + ISUID = log2(_S_ISUID), /* Set user ID on execution */ + ISGID = log2(_S_ISGID), /* Set group ID on execution */ + ISVXT = log2(_S_ISVTX), /* On directories, restricted deletion flag */ +} +mode_t :: bit_set[Mode_Bits; _mode_t] +#assert(size_of(mode_t) == size_of(_mode_t)) + +// NOTE: making these `.IFREG in m` would probably be fine too, +// but implementations make this an exclusive check so lets stick to it. + +_S_IFMT :: mode_t{ .IFBLK, .IFCHR, .IFIFO, .IFREG, .IFDIR, .IFLNK, .IFSOCK } + +// Test for a block special file. +S_ISBLK :: #force_inline proc "contextless" (m: mode_t) -> bool { + return (m & _S_IFMT) == { .IFBLK } +} + +// Test for a character special file. +S_ISCHR :: #force_inline proc "contextless" (m: mode_t) -> bool { + return (m & _S_IFMT) == { .IFCHR } +} + +// Test for a pipe or FIFO special file. +S_ISFIFO :: #force_inline proc "contextless" (m: mode_t) -> bool { + return (m & _S_IFMT) == { .IFIFO } +} + +// Test for a regular file. +S_ISREG :: #force_inline proc "contextless" (m: mode_t) -> bool { + return (m & _S_IFMT) == { .IFREG } +} + +// Test for a directory. +S_ISDIR :: #force_inline proc "contextless" (m: mode_t) -> bool { + return (m & _S_IFMT) == { .IFDIR } +} + +// Test for a symbolic link. +S_ISLNK :: #force_inline proc "contextless" (m: mode_t) -> bool { + return (m & _S_IFMT) == { .IFLNK } +} + +// Test for a socket. +S_ISSOCK :: #force_inline proc "contextless" (m: mode_t) -> bool { + return (m & _S_IFMT) == { .IFSOCK } +} + +// Test for a message queue. +S_TYPEISMQ :: #force_inline proc "contextless" (m: mode_t) -> bool { + return _S_TYPEISMQ(m) +} + +// Test for a semaphore. +S_TYPEISSEM :: #force_inline proc "contextless" (m: mode_t) -> bool { + return _S_TYPEISSEM(m) +} + +// Test for a shared memory object. +S_TYPEISSHM :: #force_inline proc "contextless" (m: mode_t) -> bool { + return _S_TYPEISSHM(m) +} + +// Test macro for a typed memory object. +S_TYPEISTMO :: #force_inline proc "contextless" (m: mode_t) -> bool { + return _S_TYPEISTMO(m) +} + +_S_IRWXU :: 0o000700 +_S_IRUSR :: 0o000400 +_S_IWUSR :: 0o000200 +_S_IXUSR :: 0o000100 + +_S_IRWXG :: 0o000070 +_S_IRGRP :: 0o000040 +_S_IWGRP :: 0o000020 +_S_IXGRP :: 0o000010 + +_S_IRWXO :: 0o000007 +_S_IROTH :: 0o000004 +_S_IWOTH :: 0o000002 +_S_IXOTH :: 0o000001 + +_S_ISUID :: 0o004000 +_S_ISGID :: 0o002000 +_S_ISVTX :: 0o001000 + +when ODIN_OS == .NetBSD { + @(private) LSTAT :: "__stat50" + @(private) LFSTAT :: "__fstat50" + @(private) LLSTAT :: "__lstat50" + @(private) LMKNOD :: "__mknod50" +} else { + @(private) LSTAT :: "stat" + INODE_SUFFIX + @(private) LFSTAT :: "fstat" + INODE_SUFFIX + @(private) LLSTAT :: "lstat" + INODE_SUFFIX + @(private) LMKNOD :: "mknod" +} + +when ODIN_OS == .Darwin { + + dev_t :: distinct c.int32_t + nlink_t :: distinct c.uint16_t + _mode_t :: distinct c.uint16_t + blkcnt_t :: distinct c.int64_t + blksize_t :: distinct c.int32_t + ino_t :: distinct c.uint64_t + + stat_t :: struct { + st_dev: dev_t, /* [XSI] ID of device containing file */ + st_mode: mode_t, /* [XSI] mode of file */ + st_nlink: nlink_t, /* [XSI] number of hard links */ + st_ino: ino_t, /* [XSI] file serial number */ + st_uid: uid_t, /* [XSI] user ID of the file */ + st_gid: gid_t, /* [XSI] group ID of the file */ + st_rdev: dev_t, /* [XSI] device ID */ + st_atim: timespec, /* [XSI] time of last access */ + st_mtim: timespec, /* [XSI] time of last data modification */ + st_ctim: timespec, /* [XSI] time of last status change */ + st_birthtimespec: timespec, /* time of file creation(birth) */ + st_size: off_t, /* [XSI] file size, in bytes */ + st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */ + st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */ + st_flags: c.uint32_t, /* user defined flags for file */ + st_gen: c.uint32_t, /* file generation number */ + st_lspare: c.int32_t, /* RESERVED */ + st_qspare: [2]c.int64_t, /* RESERVED */ + } + + S_IFBLK :: 0o060000 + S_IFCHR :: 0o020000 + S_IFIFO :: 0o010000 + S_IFREG :: 0o100000 + S_IFDIR :: 0o040000 + S_IFLNK :: 0o120000 + S_IFSOCK :: 0o140000 + + __S_IFMT :: 0o170000 + + _S_TYPEISMQ :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISSEM :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISSHM :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISTMO :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + UTIME_NOW :: -1 + UTIME_OMIT :: -2 + +} else when ODIN_OS == .FreeBSD { + + dev_t :: distinct c.uint64_t + nlink_t :: distinct c.uint64_t + _mode_t :: distinct c.uint16_t + blkcnt_t :: distinct c.int64_t + blksize_t :: distinct c.int32_t + ino_t :: distinct c.uint64_t + + when ODIN_ARCH == .i386 { + stat_t :: struct { + st_dev: dev_t, /* [XSI] ID of device containing file */ + st_ino: ino_t, /* [XSI] file serial number */ + st_nlink: nlink_t, /* [XSI] number of hard links */ + st_mode: mode_t, /* [XSI] mode of file */ + st_padding0: c.int16_t, + st_uid: uid_t, /* [XSI] user ID of the file */ + st_gid: gid_t, /* [XSI] group ID of the file */ + st_padding1: c.int32_t, + st_rdev: dev_t, /* [XSI] device ID */ + st_atim_ext: c.int32_t, + st_atim: timespec, /* [XSI] time of last access */ + st_mtim_ext: c.int32_t, + st_mtim: timespec, /* [XSI] time of last data modification */ + st_ctim_ext: c.int32_t, + st_ctim: timespec, /* [XSI] time of last status change */ + st_birthtimespec: timespec, /* time of file creation(birth) */ + st_size: off_t, /* [XSI] file size, in bytes */ + st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */ + st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */ + st_flags: c.uint32_t, /* user defined flags for file */ + st_gen: c.uint64_t, + st_spare: [10]c.uint64_t, + } + } else { + stat_t :: struct { + st_dev: dev_t, /* [XSI] ID of device containing file */ + st_ino: ino_t, /* [XSI] file serial number */ + st_nlink: nlink_t, /* [XSI] number of hard links */ + st_mode: mode_t, /* [XSI] mode of file */ + st_padding0: c.int16_t, + st_uid: uid_t, /* [XSI] user ID of the file */ + st_gid: gid_t, /* [XSI] group ID of the file */ + st_padding1: c.int32_t, + st_rdev: dev_t, /* [XSI] device ID */ + st_atim: timespec, /* [XSI] time of last access */ + st_mtim: timespec, /* [XSI] time of last data modification */ + st_ctim: timespec, /* [XSI] time of last status change */ + st_birthtimespec: timespec, /* time of file creation(birth) */ + st_size: off_t, /* [XSI] file size, in bytes */ + st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */ + st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */ + st_flags: c.uint32_t, /* user defined flags for file */ + st_gen: c.uint64_t, + st_spare: [10]c.uint64_t, + } + } + + S_IFBLK :: 0o060000 + S_IFCHR :: 0o020000 + S_IFIFO :: 0o010000 + S_IFREG :: 0o100000 + S_IFDIR :: 0o040000 + S_IFLNK :: 0o120000 + S_IFSOCK :: 0o140000 + + __S_IFMT :: 0o170000 + + _S_TYPEISMQ :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISSEM :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISSHM :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISTMO :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + UTIME_NOW :: -1 + UTIME_OMIT :: -2 + +} else when ODIN_OS == .NetBSD { + + dev_t :: distinct c.uint64_t + nlink_t :: distinct c.uint32_t + _mode_t :: distinct c.uint32_t + blkcnt_t :: distinct c.int64_t + blksize_t :: distinct c.int32_t + ino_t :: distinct c.uint64_t + + stat_t :: struct { + st_dev: dev_t, /* [XSI] ID of device containing file */ + st_mode: mode_t, /* [XSI] mode of file */ + st_ino: ino_t, /* [XSI] file serial number */ + st_nlink: nlink_t, /* [XSI] number of hard links */ + st_uid: uid_t, /* [XSI] user ID of the file */ + st_gid: gid_t, /* [XSI] group ID of the file */ + st_rdev: dev_t, /* [XSI] device ID */ + st_atim: timespec, /* [XSI] time of last access */ + st_mtim: timespec, /* [XSI] time of last data modification */ + st_ctim: timespec, /* [XSI] time of last status change */ + st_birthtimespec: timespec, /* time of file creation(birth) */ + st_size: off_t, /* [XSI] file size, in bytes */ + st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */ + st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */ + st_flags: c.uint32_t, /* user defined flags for file */ + st_gen: c.uint64_t, + st_spare: [2]c.uint32_t, + } + + S_IFBLK :: 0o060000 + S_IFCHR :: 0o020000 + S_IFIFO :: 0o010000 + S_IFREG :: 0o100000 + S_IFDIR :: 0o040000 + S_IFLNK :: 0o120000 + S_IFSOCK :: 0o140000 + + __S_IFMT :: 0o170000 + + _S_TYPEISMQ :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISSEM :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISSHM :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISTMO :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + UTIME_NOW :: (1 << 30) - 1 + UTIME_OMIT :: (1 << 30) - 2 + +} else when ODIN_OS == .OpenBSD { + + dev_t :: distinct c.int32_t + nlink_t :: distinct c.uint32_t + _mode_t :: distinct c.uint32_t + blkcnt_t :: distinct c.int64_t + blksize_t :: distinct c.int32_t + ino_t :: distinct c.uint64_t + + stat_t :: struct { + st_mode: mode_t, /* [XSI] mode of file */ + st_dev: dev_t, /* [XSI] ID of device containing file */ + st_ino: ino_t, /* [XSI] file serial number */ + st_nlink: nlink_t, /* [XSI] number of hard links */ + st_uid: uid_t, /* [XSI] user ID of the file */ + st_gid: gid_t, /* [XSI] group ID of the file */ + st_rdev: dev_t, /* [XSI] device ID */ + st_atim: timespec, /* [XSI] time of last access */ + st_mtim: timespec, /* [XSI] time of last data modification */ + st_ctim: timespec, /* [XSI] time of last status change */ + st_size: off_t, /* [XSI] file size, in bytes */ + st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */ + st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */ + st_flags: c.uint32_t, /* user defined flags for file */ + st_gen: c.int32_t, + st_birthtimespec: timespec, + } + + S_IFBLK :: 0o060000 + S_IFCHR :: 0o020000 + S_IFIFO :: 0o010000 + S_IFREG :: 0o100000 + S_IFDIR :: 0o040000 + S_IFLNK :: 0o120000 + S_IFSOCK :: 0o140000 + + __S_IFMT :: 0o170000 + + _S_TYPEISMQ :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISSEM :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISSHM :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + _S_TYPEISTMO :: #force_inline proc "contextless" (m: mode_t) -> bool { + return false + } + + UTIME_NOW :: -2 + UTIME_OMIT :: -1 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_statvfs.odin b/core/sys/posix/sys_statvfs.odin new file mode 100644 index 000000000..eb6c16806 --- /dev/null +++ b/core/sys/posix/sys_statvfs.odin @@ -0,0 +1,135 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/statvfs.h - VFS File System information structure + +foreign lib { + + /* + Obtains information about the file system containing the fildes. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/statvfs.html ]] + */ + @(link_name=LFSTATVFS) + fstatvfs :: proc(fildes: FD, buf: ^statvfs_t) -> result --- + + /* + Obtains information about the file system containing the file named by path. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/statvfs.html ]] + */ + @(link_name=LSTATVFS) + statvfs :: proc(path: cstring, buf: ^statvfs_t) -> result --- +} + +VFS_Flag_Bits :: enum c.ulong { + // Read-only file system. + RDONLY = log2(ST_RDONLY), + // Does not support the semantics of the ST_ISUID and ST_ISGID file mode bits. + NOSUID = log2(ST_NOSUID), +} +VFS_Flags :: bit_set[VFS_Flag_Bits; c.ulong] + +when ODIN_OS == .NetBSD { + @(private) LFSTATVFS :: "__fstatvfs90" + @(private) LSTATVFS :: "__statvfs90" +} else { + @(private) LFSTATVFS :: "fstatvfs" + @(private) LSTATVFS :: "statvfs" +} + +when ODIN_OS == .Darwin || ODIN_OS == .OpenBSD { + + fsblkcnt_t :: distinct c.uint + + statvfs_t :: struct { + f_bsize: c.ulong, /* [PSX] file system block size */ + f_frsize: c.ulong, /* [PSX] fundamental file system block size */ + f_blocks: fsblkcnt_t, /* [PSX] total number of blocks on file system in units of f_frsize */ + f_bfree: fsblkcnt_t, /* [PSX] total number of free blocks */ + f_bavail: fsblkcnt_t, /* [PSX] number of free blocks available to non-privileged process */ + f_files: fsblkcnt_t, /* [PSX] total number of file serial numbers */ + f_ffree: fsblkcnt_t, /* [PSX] total number of free file serial numbers */ + f_favail: fsblkcnt_t, /* [PSX] number of file serial numbers available to non-privileged process */ + f_fsid: c.ulong, /* [PSX] file system ID */ + f_flag: VFS_Flags, /* [PSX] bit mask of f_flag values */ + f_namemax: c.ulong, /* [PSX] maximum filename length */ + } + + ST_RDONLY :: 0x00000001 + ST_NOSUID :: 0x00000002 + +} else when ODIN_OS == .FreeBSD { + + fsblkcnt_t :: distinct c.uint64_t + + statvfs_t :: struct { + f_bavail: fsblkcnt_t, /* [PSX] number of free blocks available to non-privileged process */ + f_bfree: fsblkcnt_t, /* [PSX] total number of free blocks */ + f_blocks: fsblkcnt_t, /* [PSX] total number of blocks on file system in units of f_frsize */ + f_favail: fsblkcnt_t, /* [PSX] number of file serial numbers available to non-privileged process */ + f_ffree: fsblkcnt_t, /* [PSX] total number of free file serial numbers */ + f_files: fsblkcnt_t, /* [PSX] total number of file serial numbers */ + f_bsize: c.ulong, /* [PSX] file system block size */ + f_flag: VFS_Flags, /* [PSX] bit mask of f_flag values */ + f_frsize: c.ulong, /* [PSX] fundamental file system block size */ + f_fsid: c.ulong, /* [PSX] file system ID */ + f_namemax: c.ulong, /* [PSX] maximum filename length */ + } + + ST_RDONLY :: 0x00000001 + ST_NOSUID :: 0x00000002 + +} else when ODIN_OS == .NetBSD { + + fsblkcnt_t :: distinct c.uint64_t + + @(private) + _VFS_NAMELEN :: 1024 + + @(private) + fsid_t :: struct { + __fsid_val: [2]c.int, + } + + statvfs_t :: struct { + f_flag: VFS_Flags, /* [PSX] bit mask of f_flag values */ + f_bsize: c.ulong, /* [PSX] file system block size */ + f_frsize: c.ulong, /* [PSX] fundamental file system block size */ + f_iosize: c.ulong, + f_blocks: fsblkcnt_t, /* [PSX] total number of blocks on file system in units of f_frsize */ + f_bfree: fsblkcnt_t, /* [PSX] total number of free blocks */ + f_bavail: fsblkcnt_t, /* [PSX] number of free blocks available to non-privileged process */ + f_bresvd: fsblkcnt_t, + f_files: fsblkcnt_t, /* [PSX] total number of file serial numbers */ + f_ffree: fsblkcnt_t, /* [PSX] total number of free file serial numbers */ + f_favail: fsblkcnt_t, /* [PSX] number of file serial numbers available to non-privileged process */ + f_fresvd: fsblkcnt_t, + f_syncreads: c.uint64_t, + f_syncwrites: c.uint64_t, + f_asyncreads: c.uint64_t, + f_asyncwrites: c.uint64_t, + f_fsidx: fsid_t, + f_fsid: c.ulong, /* [PSX] file system ID */ + f_namemax: c.ulong, /* [PSX] maximum filename length */ + f_owner: uid_t, + f_spare: [4]c.uint64_t, + f_fstypename: [_VFS_NAMELEN]c.char `fmt:"s,0"`, + f_mntonname: [_VFS_NAMELEN]c.char `fmt:"s,0"`, + f_mntfromname: [_VFS_NAMELEN]c.char `fmt:"s,0"`, + f_mntfromlabel: [_VFS_NAMELEN]c.char `fmt:"s,0"`, + } + + ST_RDONLY :: 0x00000001 + ST_NOSUID :: 0x00000008 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_time.odin b/core/sys/posix/sys_time.odin new file mode 100644 index 000000000..093fdd688 --- /dev/null +++ b/core/sys/posix/sys_time.odin @@ -0,0 +1,82 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/time.h - time types + +foreign lib { + /* + Store the current value of timer into value. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getitimer.html ]] + */ + @(link_name=LGETITIMER) + getitimer :: proc(which: ITimer, value: ^itimerval) -> result --- + + /* + Set the timer to the value given, and store the previous value in ovalue if it is not nil. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getitimer.html ]] + */ + @(link_name=LSETITIMER) + setitimer :: proc(which: ITimer, value: ^itimerval, ovalue: ^itimerval) -> result --- + + /* + Obtains the current time. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gettimeofday.html ]] + */ + @(link_name=LGETTIMEOFDAY) + gettimeofday :: proc(tp: ^timeval, tzp: rawptr = nil) -> result --- + + /* + Sets the access and modification times of the file at the given path. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html ]] + */ + @(link_name=LUTIMES) + utimes :: proc(path: cstring, times: ^[2]timeval) -> result --- +} + +ITimer :: enum c.int { + // Decrements in real time. + REAL = ITIMER_REAL, + // Decrements in process virtual time, only when the process is executing. + VIRTUAL = ITIMER_VIRTUAL, + // Decrements both in process virtual time and when the system is running on + // behalf of the process. + PROF = ITIMER_PROF, +} + +when ODIN_OS == .NetBSD { + @(private) LGETITIMER :: "__getitimer50" + @(private) LSETITIMER :: "__setitimer50" + @(private) LGETTIMEOFDAY :: "__gettimeofday50" + @(private) LUTIMES :: "__utimes50" +} else { + @(private) LGETITIMER :: "getitimer" + @(private) LSETITIMER :: "setitimer" + @(private) LGETTIMEOFDAY :: "gettimeofday" + @(private) LUTIMES :: "utimes" +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + itimerval :: struct { + it_interval: timeval, /* [PSX] timer interval */ + it_value: timeval, /* [PSX] current value */ + } + + ITIMER_REAL :: 0 + ITIMER_VIRTUAL :: 1 + ITIMER_PROF :: 2 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_times.odin b/core/sys/posix/sys_times.odin new file mode 100644 index 000000000..685ced515 --- /dev/null +++ b/core/sys/posix/sys_times.odin @@ -0,0 +1,38 @@ +package posix + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/times.h - file access and modification times structure + +foreign lib { + /* + Get time accounting information. + + Returns: -1 (setting errno) on failure, the elapsed real time, since an arbitrary point in the past + */ + @(link_name=LTIMES) + times :: proc(buffer: ^tms) -> clock_t --- +} + +when ODIN_OS == .NetBSD { + @(private) LTIMES :: "__times13" +} else { + @(private) LTIMES :: "times" +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + tms :: struct { + tms_utime: clock_t, /* [PSX] user CPU time */ + tms_stime: clock_t, /* [PSX] system CPU time */ + tms_cutime: clock_t, /* [PSX] terminated children user CPU time */ + tms_cstime: clock_t, /* [PSX] terminated children system CPU time */ + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_uio.odin b/core/sys/posix/sys_uio.odin new file mode 100644 index 000000000..01664e576 --- /dev/null +++ b/core/sys/posix/sys_uio.odin @@ -0,0 +1,42 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import libc "system:System.framework" +} else { + foreign import libc "system:c" +} + +// sys/uio.h - definitions for vector I/O operations + +foreign libc { + /* + Equivalent to read() but takes a vector of inputs. + + iovcnt can be 0..=IOV_MAX in length. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html ]] + */ + readv :: proc(fildes: FD, iov: [^]iovec, iovcnt: c.int) -> c.ssize_t --- + + /* + Equivalent to write() but takes a vector of inputs. + + iovcnt can be 0..=IOV_MAX in length. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html ]] + */ + writev :: proc(fildes: FD, iov: [^]iovec, iovcnt: c.int) -> c.ssize_t --- +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + iovec :: struct { + iov_base: rawptr, /* [PSX] base address of I/O memory region */ + iov_len: c.size_t, /* [PSX] size of the region iov_base points to */ + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_un.odin b/core/sys/posix/sys_un.odin new file mode 100644 index 000000000..146882051 --- /dev/null +++ b/core/sys/posix/sys_un.odin @@ -0,0 +1,17 @@ +package posix + +import "core:c" + +// sys/un.h = definitions for UNIX domain sockets + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + sockaddr_un :: struct { + sun_len: c.uchar, /* sockaddr len including nil */ + sun_family: sa_family_t, /* [PSX] address family */ + sun_path: [104]c.char, /* [PSX] socket pathname */ + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_utsname.odin b/core/sys/posix/sys_utsname.odin new file mode 100644 index 000000000..803f40ffd --- /dev/null +++ b/core/sys/posix/sys_utsname.odin @@ -0,0 +1,55 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/utsname.h = system name structure + +foreign lib { + /* + Stores information identifying the current system in the given structure. + + Returns: non-negative on success, -1 (setting errno) on failure + + NOTE: have a look at `core:sys/info` for similar/better system information. + + Example: + uname: posix.utsname + posix.uname(&uname) + fmt.printfln("%#v", uname) + + Possible Output: + utsname{ + sysname = Darwin, + nodename = Laytans-MacBook-Pro.local, + release = 23.5.0, + version = Darwin Kernel Version 23.5.0: Wed May 1 20:16:51 PDT 2024; root:xnu-11331.111.3~1/RELEASE_ARM64_T8103, + machine = arm64, + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/uname.html ]] + */ + uname :: proc(uname: ^utsname) -> c.int --- +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + @(private) + _SYS_NAMELEN :: 256 + + utsname :: struct { + sysname: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] name of OS */ + nodename: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] name of this network node */ + release: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] release level */ + version: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] version level */ + machine: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] hardware type */ + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/sys_wait.odin b/core/sys/posix/sys_wait.odin new file mode 100644 index 000000000..6d0336e80 --- /dev/null +++ b/core/sys/posix/sys_wait.odin @@ -0,0 +1,380 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// sys/wait.h - declarations for waiting + +foreign lib { + /* + Obtains status information pertaining to one of the caller's child processes. + + Returns: -1 (setting errno) on failure or signal on calling process, the pid of the process that caused the return otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html ]] + */ + wait :: proc(stat_loc: ^c.int) -> pid_t --- + + /* + Obtains status information pertaining to the given pid specifier. + + If pid is -1, status is requested for any child process. + If pid is greater than 0, it specifies the process ID of a single child process. + If pid is 0, it specifies any child process whose process group ID is equal to that of the call. + If pid is < -1, status is requested for any child whose process group ID is the absolute value of pid. + + Returns: -1 (setting errno) on failure or signal on calling process, 0 if NOHANG and status is not available, the pid of the process that caused the return otherwise + + Example: + // The following example demonstrates the use of waitpid(), fork(), and the macros used to + // interpret the status value returned by waitpid() (and wait()). The code segment creates a + // child process which does some unspecified work. Meanwhile the parent loops performing calls + // to waitpid() to monitor the status of the child. The loop terminates when child termination + // is detected. + + child_pid := posix.fork(); switch child_pid { + case -1: // `fork` failed. + panic("fork failed") + + case 0: // This is the child. + + // Do some work... + + case: + for { + status: i32 + wpid := posix.waitpid(child_pid, &status, { .UNTRACED, .CONTINUED }) + if wpid == -1 { + panic("waitpid failure") + } + + switch { + case posix.WIFEXITED(status): + fmt.printfln("child exited, status=%v", posix.WEXITSTATUS(status)) + case posix.WIFSIGNALED(status): + fmt.printfln("child killed (signal %v)", posix.WTERMSIG(status)) + case posix.WIFSTOPPED(status): + fmt.printfln("child stopped (signal %v", posix.WSTOPSIG(status)) + case posix.WIFCONTINUED(status): + fmt.println("child continued") + case: + // Should never happen. + fmt.println("unexpected status (%x)", status) + } + + if posix.WIFEXITED(status) || posix.WIFSIGNALED(status) { + break + } + } + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html ]] + */ + waitpid :: proc(pid: pid_t, stat_loc: ^c.int, options: Wait_Flags) -> pid_t --- + + /* + Obtains status information pertaining to the given idtype_t and id specifier. + + Returns: 0 if WNOHANG and no status available, 0 if child changed state, -1 (setting errno) on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/waitid.html ]] + */ + waitid :: proc(idtype: idtype_t, id: id_t, infop: ^siginfo_t, options: Wait_Flags) -> c.int --- +} + +// If terminated normally. +WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WIFEXITED(x) +} + +// If WIFEXITED is true, returns the exit status. +WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int { + return _WEXITSTATUS(x) +} + +// If terminated due to an uncaught signal. +WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WIFSIGNALED(x) +} + +// If WIFSIGNALED is true, returns the signal. +WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return _WTERMSIG(x) +} + +// If status was returned for a child process that is currently stopped. +WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WIFSTOPPED(x) +} + +// If WIFSTOPPED, the signal that caused the child process to stop. +WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return _WSTOPSIG(x) +} + +// If status was returned for a child process that has continued from a job control stop. +WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WIFCONTINUED(x) +} + +idtype_t :: enum c.int { + // Wait for any children and `id` is ignored. + P_ALL, + // Wait for any child wiith a process group ID equal to `id`. + P_PID, + // Wait for any child with a process group ID equal to `id`. + P_PGID, +} + +Wait_Flag_Bits :: enum c.int { + // Report the status of any continued child process specified by pid whose status has not been + // reported since it continued from a job control stop. + CONTINUED = log2(WCONTINUED), + // Don't suspend execution of the calling thread if status is not immediately available for one + // of the child processes specified by pid. + NOHANG = log2(WNOHANG), + // The status of any child process specified by pid that are stopped, and whose status has not + // yet been reported since they stopped, shall also be reported to the requesting process. + UNTRACED = log2(WUNTRACED), + + // Following are only available on `waitid`, not `waitpid`. + + // Wait for processes that have exited. + EXITED = log2(WEXITED), + // Keep the process whose status is returned in a waitable state, so it may be waited on again. + NOWAIT = log2(WNOWAIT), + // Children that have stopped upon receipt of a signal, and whose status either hasn't been reported + // or has been reported but that report was called with NOWAIT. + STOPPED = log2(WSTOPPED), +} +Wait_Flags :: bit_set[Wait_Flag_Bits; c.int] + +when ODIN_OS == .Darwin { + + id_t :: distinct c.uint + + WCONTINUED :: 0x00000010 + WNOHANG :: 0x00000001 + WUNTRACED :: 0x00000002 + + WEXITED :: 0x00000004 + WNOWAIT :: 0x00000020 + WSTOPPED :: 0x00000008 + + @(private) + _WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int { + return x & 0o177 + } + + @(private) + _WSTOPPED :: 0o177 + + @(private) + _WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WSTATUS(x) == 0 + } + + @(private) + _WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int { + return x >> 8 + } + + @(private) + _WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0 + } + + @(private) + _WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return Signal(_WSTATUS(x)) + } + + @(private) + _WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WSTATUS(x) == _WSTOPPED && WSTOPSIG(x) != .SIGCONT + } + + @(private) + _WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return Signal(x >> 8) + } + + @(private) + _WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WSTATUS(x) == _WSTOPPED && WSTOPSIG(x) == .SIGCONT + } + +} else when ODIN_OS == .FreeBSD { + + id_t :: distinct c.int64_t + + WCONTINUED :: 4 + WNOHANG :: 1 + WUNTRACED :: 2 + + WEXITED :: 16 + WNOWAIT :: 8 + WSTOPPED :: 2 + + @(private) + _WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int { + return x & 0o177 + } + + @(private) + _WSTOPPED :: 0o177 + + @(private) + _WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WSTATUS(x) == 0 + } + + @(private) + _WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int { + return x >> 8 + } + + @(private) + _WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0 && x != c.int(Signal.SIGCONT) + } + + @(private) + _WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return Signal(_WSTATUS(x)) + } + + @(private) + _WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WSTATUS(x) == _WSTOPPED + } + + @(private) + _WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return Signal(x >> 8) + } + + @(private) + _WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool { + return x == c.int(Signal.SIGCONT) + } +} else when ODIN_OS == .NetBSD { + + id_t :: distinct c.uint32_t + + WCONTINUED :: 0x00000010 + WNOHANG :: 0x00000001 + WUNTRACED :: 0x00000002 + + WEXITED :: 0x00000020 + WNOWAIT :: 0x00010000 + WSTOPPED :: 0x00000002 + + @(private) + _WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int { + return x & 0o177 + } + + @(private) + _WSTOPPED :: 0o177 + + @(private) + _WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WSTATUS(x) == 0 + } + + @(private) + _WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int { + return (x >> 8) & 0x000000ff + } + + @(private) + _WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool { + return !WIFSTOPPED(x) && !WIFCONTINUED(x) && !WIFEXITED(x) + } + + @(private) + _WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return Signal(_WSTATUS(x)) + } + + @(private) + _WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WSTATUS(x) == _WSTOPPED && !WIFCONTINUED(x) + } + + @(private) + _WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return Signal((x >> 8) & 0xff) + } + + @(private) + _WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool { + return x == 0xffff + } + +} else when ODIN_OS == .OpenBSD { + + id_t :: distinct c.uint32_t + + WCONTINUED :: 0x00000010 + WNOHANG :: 0x00000001 + WUNTRACED :: 0x00000002 + + WEXITED :: 0x00000020 + WNOWAIT :: 0x00010000 + WSTOPPED :: 0x00000002 + + @(private) + _WSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int { + return x & 0o177 + } + + @(private) + _WSTOPPED :: 0o177 + @(private) + _WCONTINUED :: 0o177777 + + @(private) + _WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WSTATUS(x) == 0 + } + + @(private) + _WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int { + return (x >> 8) & 0x000000ff + } + + @(private) + _WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WSTATUS(x) != _WSTOPPED && _WSTATUS(x) != 0 + } + + @(private) + _WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return Signal(_WSTATUS(x)) + } + + @(private) + _WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool { + return (x & 0xff) == _WSTOPPED + } + + @(private) + _WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return Signal((x >> 8) & 0xff) + } + + @(private) + _WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool { + return (x & _WCONTINUED) == _WCONTINUED + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/termios.odin b/core/sys/posix/termios.odin new file mode 100644 index 000000000..372e67e06 --- /dev/null +++ b/core/sys/posix/termios.odin @@ -0,0 +1,475 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// termios.h - define values for termios + +foreign lib { + /* + Get the input baud rate. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html ]] + */ + cfgetispeed :: proc(termios_p: ^termios) -> speed_t --- + + /* + Set the input baud rate. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html ]] + */ + cfsetispeed :: proc(termios_p: ^termios, rate: speed_t) -> result --- + + /* + Get the output baud rate. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html ]] + */ + cfgetospeed :: proc(termios_p: ^termios) -> speed_t --- + + /* + Set the output baud rate. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html ]] + */ + cfsetospeed :: proc(termios_p: ^termios, rate: speed_t) -> result --- + + /* + Wait for transmission of output. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html ]] + */ + tcdrain :: proc(fildes: FD) -> result --- + + /* + Suspend or restart the transmission or reception of data. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html ]] + */ + tcflow :: proc(fildes: FD, action: TC_Action) -> result --- + + /* + Flush non-transmitted output data, non-read input data, or both. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html ]] + */ + tcflush :: proc(fildes: FD, queue_selector: TC_Queue) -> result --- + + /* + Get the parameters associated with the terminal. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html ]] + */ + tcgetattr :: proc(fildes: FD, termios_p: ^termios) -> result --- + + /* + Get the process group ID for the session leader for the controlling terminal. + + Returns: -1 (setting errno) on failure, the pid otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html ]] + */ + tcgetsid :: proc(fildes: FD) -> pid_t --- + + /* + Send a break for a specific duration. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html ]] + */ + tcsendbreak :: proc(fildes: FD, duration: c.int) -> result --- + + /* + Set the parameters associated with the terminal. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html ]] + */ + tcsetattr :: proc(fildes: FD, optional_actions: c.int, termios_p: ^termios) -> result --- +} + +Control_Char :: enum c.int { + VEOF = VEOF, + VEOL = VEOL, + VERASE = VERASE, + VINTR = VINTR, + VKILL = VKILL, + VMIN = VMIN, + VQUIT = VQUIT, + VSTART = VSTART, + VSTOP = VSTOP, + VSUSP = VSUSP, + VTIME = VTIME, + + NCCS = NCCS-1, +} +#assert(len(#sparse [Control_Char]cc_t) == NCCS) + +CInput_Flag_Bits :: enum tcflag_t { + IGNBRK = log2(IGNBRK), /* ignore BREAK condition */ + BRKINT = log2(BRKINT), /* map BREAK to SIGINTR */ + IGNPAR = log2(IGNPAR), /* ignore (discard) parity errors */ + PARMRK = log2(PARMRK), /* mark parity and framing errors */ + INPCK = log2(INPCK), /* enable checking of parity errors */ + ISTRIP = log2(ISTRIP), /* strip 8th bit off chars */ + INLCR = log2(INLCR), /* map NL into CR */ + IGNCR = log2(IGNCR), /* ignore CR */ + ICRNL = log2(ICRNL), /* map CR to NL (ala CRMOD) */ + IXON = log2(IXON), /* enable output flow control */ + IXOFF = log2(IXOFF), /* enable input flow control */ + IXANY = log2(IXANY), /* any char will restart after stop */ +} +CInput_Flags :: bit_set[CInput_Flag_Bits; tcflag_t] + +CLocal_Flag_Bits :: enum tcflag_t { + ECHO = log2(ECHO), /* visual erase for line kill */ + ECHOE = log2(ECHOE), /* visually erase chars */ + ECHOK = log2(ECHOK), /* echo NL after line kill */ + ECHONL = log2(ECHONL), /* echo NL even if ECHO is off */ + ICANON = log2(ICANON), /* canonicalize input lines */ + IEXTEN = log2(IEXTEN), /* enable DISCARD and LNEXT */ + ISIG = log2(ISIG), /* enable signals INTR, QUIT, [D]SUSP */ + NOFLSH = log2(NOFLSH), /* don't flush after interrupt */ + TOSTOP = log2(TOSTOP), /* stop background jobs from output */ +} +CLocal_Flags :: bit_set[CLocal_Flag_Bits; tcflag_t] + +CControl_Flag_Bits :: enum tcflag_t { + // CS5 = log2(CS5), /* 5 bits (pseudo) (default) */ + CS6 = log2(CS6), /* 6 bits */ + CS7 = log2(CS7), /* 7 bits */ + CS8 = log2(CS8), /* 8 bits */ + CSTOPB = log2(CSTOPB), /* send 2 stop bits */ + CREAD = log2(CREAD), /* enable receiver */ + PARENB = log2(PARENB), /* parity enable */ + PARODD = log2(PARODD), /* odd parity, else even */ + HUPCL = log2(HUPCL), /* hang up on last close */ + CLOCAL = log2(CLOCAL), /* ignore modem status lines */ +} +CControl_Flags :: bit_set[CControl_Flag_Bits; tcflag_t] + +// character size mask +CSIZE :: CControl_Flags{ .CS6, .CS7, .CS8 } + +COutput_Flag_Bits :: enum tcflag_t { + OPOST = log2(OPOST), /* enable following output processing */ + ONLCR = log2(ONLCR), /* map NL to CR-NL (ala CRMOD) */ + OCRNL = log2(OCRNL), /* map CR to NL on output */ + ONOCR = log2(ONOCR), /* no CR output at column 0 */ + ONLRET = log2(ONLRET), /* NL performs CR function */ + OFDEL = log2(OFDEL), /* fill is DEL, else NUL */ + OFILL = log2(OFILL), /* use fill characters for delay */ + // NL0 = log2(NL0), /* \n delay 0 (default) */ + NL1 = log2(NL1), /* \n delay 1 */ + // CR0 = log2(CR0), /* \r delay 0 (default) */ + CR1 = log2(CR1), /* \r delay 1 */ + CR2 = log2(CR2), /* \r delay 2 */ + CR3 = log2(CR3), /* \r delay 3 */ + // TAB0 = log2(TAB0),/* horizontal tab delay 0 (default) */ + TAB1 = log2(TAB1), /* horizontal tab delay 1 */ + TAB3 = log2(TAB3), /* horizontal tab delay 3 */ + // BS0 = log2(BS0), /* \b delay 0 (default) */ + BS1 = log2(BS1), /* \b delay 1 */ + // VT0 = log2(VT0), /* vertical tab delay 0 (default) */ + VT1 = log2(VT1), /* vertical tab delay 1 */ + // FF0 = log2(FF0), /* form feed delay 0 (default) */ + FF1 = log2(FF1), /* form feed delay 1 */ +} +COutput_Flags :: bit_set[COutput_Flag_Bits; tcflag_t] + +// \n delay mask +NLDLY :: COutput_Flags{ .NL1, COutput_Flag_Bits(9) } +// \r delay mask +CRDLY :: COutput_Flags{ .CR1, .CR2, .CR3 } +// horizontal tab delay mask +TABDLY :: COutput_Flags{ .TAB1, .TAB3, COutput_Flag_Bits(2) } +// \b delay mask +BSDLY :: COutput_Flags{ .BS1 } +// vertical tab delay mask +VTDLY :: COutput_Flags{ .VT1 } +// form feed delay mask +FFDLY :: COutput_Flags{ .FF1 } + +speed_t :: enum _speed_t { + B0 = B0, + B50 = B50, + B75 = B75, + B110 = B110, + B134 = B134, + B150 = B150, + B200 = B200, + B300 = B300, + B600 = B600, + B1200 = B1200, + B1800 = B1800, + B2400 = B2400, + B4800 = B4800, + B9600 = B9600, + B19200 = B19200, + B38400 = B38400, +} + +TC_Action :: enum c.int { + TCIOFF = TCIOFF, + TCION = TCION, + TCOOFF = TCOOFF, + TCOON = TCOON, +} + +TC_Queue :: enum c.int { + TCIFLUSH = TCIFLUSH, + TCOFLUSH = TCOFLUSH, + TCIOFLUSH = TCIOFLUSH, +} + +when ODIN_OS == .Darwin { + + cc_t :: distinct c.uchar + _speed_t :: distinct c.ulong + tcflag_t :: distinct c.ulong + + termios :: struct { + c_iflag: CInput_Flags, /* [XBD] input flags */ + c_oflag: COutput_Flags, /* [XBD] output flags */ + c_cflag: CControl_Flags, /* [XBD] control flags */ + c_lflag: CLocal_Flags, /* [XBD] local flag */ + c_cc: #sparse [Control_Char]cc_t, /* [XBD] control chars */ + c_ispeed: speed_t, /* input speed */ + c_ospeed: speed_t, /* output speed */ + } + + NCCS :: 20 + + VEOF :: 0 + VEOL :: 1 + VERASE :: 3 + VINTR :: 8 + VKILL :: 5 + VMIN :: 16 + VQUIT :: 9 + VSTART :: 12 + VSTOP :: 13 + VSUSP :: 10 + VTIME :: 17 + + IGNBRK :: 0x00000001 + BRKINT :: 0x00000002 + IGNPAR :: 0x00000004 + PARMRK :: 0x00000008 + INPCK :: 0x00000010 + ISTRIP :: 0x00000020 + INLCR :: 0x00000040 + IGNCR :: 0x00000080 + ICRNL :: 0x00000100 + IXON :: 0x00000200 + IXOFF :: 0x00000400 + IXANY :: 0x00000800 + + OPOST :: 0x00000001 + ONLCR :: 0x00000002 + OCRNL :: 0x00000010 + ONOCR :: 0x00000020 + ONLRET :: 0x00000040 + OFDEL :: 0x00020000 + OFILL :: 0x00000080 + _NLDLY :: 0x00000300 + NL0 :: 0x00000000 + NL1 :: 0x00000100 + _CRDLY :: 0x00003000 + CR0 :: 0x00000000 + CR1 :: 0x00001000 + CR2 :: 0x00002000 + CR3 :: 0x00003000 + _TABDLY :: 0x00000c04 + TAB0 :: 0x00000000 + TAB1 :: 0x00000400 + TAB3 :: 0x00000800 + _BSDLY :: 0x00008000 + BS0 :: 0x00000000 + BS1 :: 0x00008000 + _VTDLY :: 0x00010000 + VT0 :: 0x00000000 + VT1 :: 0x00010000 + _FFDLY :: 0x00004000 + FF0 :: 0x00000000 + FF1 :: 0x00004000 + + B0 :: 0 + B50 :: 50 + B75 :: 75 + B110 :: 110 + B134 :: 134 + B150 :: 150 + B200 :: 200 + B300 :: 300 + B600 :: 600 + B1200 :: 1200 + B1800 :: 1800 + B2400 :: 2400 + B4800 :: 4800 + B9600 :: 9600 + B19200 :: 19200 + B38400 :: 38400 + + _CSIZE :: 0x00000300 + CS5 :: 0x00000000 + CS6 :: 0x00000100 + CS7 :: 0x00000200 + CS8 :: 0x00000300 + CSTOPB :: 0x00000400 + CREAD :: 0x00000800 + PARENB :: 0x00001000 + PARODD :: 0x00002000 + HUPCL :: 0x00004000 + CLOCAL :: 0x00008000 + + ECHO :: 0x00000008 + ECHOE :: 0x00000002 + ECHOK :: 0x00000004 + ECHONL :: 0x00000010 + ICANON :: 0x00000100 + IEXTEN :: 0x00000400 + ISIG :: 0x00000080 + NOFLSH :: 0x80000000 + TOSTOP :: 0x00400000 + + TCIFLUSH :: 1 + TCOFLUSH :: 2 + TCIOFLUSH :: 3 + + TCIOFF :: 3 + TCION :: 4 + TCOOFF :: 1 + TCOON :: 2 + +} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + cc_t :: distinct c.uchar + _speed_t :: distinct c.uint + tcflag_t :: distinct c.uint + + termios :: struct { + c_iflag: CInput_Flags, /* [XBD] input flags */ + c_oflag: COutput_Flags, /* [XBD] output flags */ + c_cflag: CControl_Flags, /* [XBD] control flags */ + c_lflag: CLocal_Flags, /* [XBD] local flag */ + c_cc: #sparse [Control_Char]cc_t, /* [XBD] control chars */ + c_ispeed: speed_t, /* input speed */ + c_ospeed: speed_t, /* output speed */ + } + + NCCS :: 20 + + VEOF :: 0 + VEOL :: 1 + VERASE :: 3 + VINTR :: 8 + VKILL :: 5 + VMIN :: 16 + VQUIT :: 9 + VSTART :: 12 + VSTOP :: 13 + VSUSP :: 10 + VTIME :: 17 + + IGNBRK :: 0x00000001 + BRKINT :: 0x00000002 + IGNPAR :: 0x00000004 + PARMRK :: 0x00000008 + INPCK :: 0x00000010 + ISTRIP :: 0x00000020 + INLCR :: 0x00000040 + IGNCR :: 0x00000080 + ICRNL :: 0x00000100 + IXON :: 0x00000200 + IXOFF :: 0x00000400 + IXANY :: 0x00000800 + + OPOST :: 0x00000001 + ONLCR :: 0x00000002 + OCRNL :: 0x00000010 + when ODIN_OS == .OpenBSD { + ONOCR :: 0x00000040 + ONLRET :: 0x00000080 + } else { + ONOCR :: 0x00000020 + ONLRET :: 0x00000040 + } + OFDEL :: 0x00020000 // NOTE: not in headers + OFILL :: 0x00000080 // NOTE: not in headers + _NLDLY :: 0x00000300 // NOTE: not in headers + NL0 :: 0x00000000 // NOTE: not in headers + NL1 :: 0x00000100 // NOTE: not in headers + _CRDLY :: 0x00003000 // NOTE: not in headers + CR0 :: 0x00000000 // NOTE: not in headers + CR1 :: 0x00001000 // NOTE: not in headers + CR2 :: 0x00002000 // NOTE: not in headers + CR3 :: 0x00003000 // NOTE: not in headers + _TABDLY :: 0x00000004 // NOTE: not in headers (netbsd) + TAB0 :: 0x00000000 // NOTE: not in headers (netbsd) + TAB1 :: 0x00000004 // NOTE: not in headers + TAB3 :: 0x00000004 // NOTE: not in headers (netbsd) + _BSDLY :: 0x00008000 // NOTE: not in headers + BS0 :: 0x00000000 // NOTE: not in headers + BS1 :: 0x00008000 // NOTE: not in headers + _VTDLY :: 0x00010000 // NOTE: not in headers + VT0 :: 0x00000000 // NOTE: not in headers + VT1 :: 0x00010000 // NOTE: not in headers + _FFDLY :: 0x00004000 // NOTE: not in headers + FF0 :: 0x00000000 // NOTE: not in headers + FF1 :: 0x00004000 // NOTE: not in headers + + B0 :: 0 + B50 :: 50 + B75 :: 75 + B110 :: 110 + B134 :: 134 + B150 :: 150 + B200 :: 200 + B300 :: 300 + B600 :: 600 + B1200 :: 1200 + B1800 :: 1800 + B2400 :: 2400 + B4800 :: 4800 + B9600 :: 9600 + B19200 :: 19200 + B38400 :: 38400 + + _CSIZE :: 0x00000300 + CS5 :: 0x00000000 + CS6 :: 0x00000100 + CS7 :: 0x00000200 + CS8 :: 0x00000300 + CSTOPB :: 0x00000400 + CREAD :: 0x00000800 + PARENB :: 0x00001000 + PARODD :: 0x00002000 + HUPCL :: 0x00004000 + CLOCAL :: 0x00008000 + + ECHO :: 0x00000008 + ECHOE :: 0x00000002 + ECHOK :: 0x00000004 + ECHONL :: 0x00000010 + ICANON :: 0x00000100 + IEXTEN :: 0x00000400 + ISIG :: 0x00000080 + NOFLSH :: 0x80000000 + TOSTOP :: 0x00400000 + + TCIFLUSH :: 1 + TCOFLUSH :: 2 + TCIOFLUSH :: 3 + + TCIOFF :: 3 + TCION :: 4 + TCOOFF :: 1 + TCOON :: 2 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/time.odin b/core/sys/posix/time.odin new file mode 100644 index 000000000..9b91c9558 --- /dev/null +++ b/core/sys/posix/time.odin @@ -0,0 +1,234 @@ +package posix + +import "core:c" +import "core:c/libc" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// time.h - time types + +foreign lib { + /* + Convert the broken down time in the structure to a string form: Sun Sep 16 01:03:52 1973\n\0 + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime_r.html ]] + */ + asctime_r :: proc(tm: ^tm, buf: [^]c.char) -> cstring --- + + /* + Convert a time value to a date and time string in the same format as asctime(). + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ctime_r.html ]] + */ + @(link_name=LCTIMER) + ctime_r :: proc(clock: ^time_t, buf: [^]c.char) -> cstring --- + + /* + Converts the time in seconds since epoch to a broken-down tm struct. + + Returns: nil (setting errno) on failure, the result pointer on success. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gmtime_r.html ]] + */ + @(link_name=LGMTIMER) + gmtime_r :: proc(timer: ^time_t, result: ^tm) -> ^tm --- + + /* + Convert the time in seconds since epoch to a broken-down tm struct in local time. + + Returns: nil (setting errno) on failure, the result pointer on success. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/localtime_r.html ]] + */ + @(link_name=LLOCALTIMER) + localtime_r :: proc(timer: ^time_t, result: ^tm) -> ^tm --- + + /* + Returns the resolution of any clock. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html ]] + */ + @(link_name=LCLOCKGETRES) + clock_getres :: proc(clock_id: Clock, res: ^timespec) -> result --- + + /* + Returns the current value tp for the specified clock, clock_id. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html ]] + */ + @(link_name=LCLOCKGETTIME) + clock_gettime :: proc(clock_id: Clock, tp: ^timespec) -> result --- + + /* + Sets the specified clock's time. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html ]] + */ + @(link_name=LCLOCKSETTIME) + clock_settime :: proc(clock_id: Clock, tp: ^timespec) -> result --- + + /* + Converts a string representation of a date or time into a broken-down time. + + Returns: nil (setting getdate_err) on failure, the broken-down time otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdate.html ]] + */ + getdate :: proc(string: cstring) -> ^tm --- + + /* + Causes the current thread to be suspended from execution until either the time interval + specified by rqtp has elapsed or a signal is delivered. + + Returns: -1 on failure (setting errno), if it was due to a signal, rmtp will be filled with the + remaining time, 0 if all time has been slept + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html ]] + */ + @(link_name=LNANOSLEEP) + nanosleep :: proc(rqtp: ^timespec, rmtp: ^timespec) -> result --- + + /* + Converts the character string to values which are stored in tm, using the specified format. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strptime.html ]] + */ + strptime :: proc(buf: [^]c.char, format: cstring, tm: ^tm) -> cstring --- + + /* + Uses the value of the environment variable TZ (or default) to set time conversion info. + + `daylight` is set to whether daylight saving time conversion should be done. + `timezone` is set to the difference, in seconds, between UTC and local standard time. + `tzname` is set by `tzname[0] = "std"` and `tzname[1] = "dst"` + + Example: + posix.tzset() + fmt.println(posix.tzname) + fmt.println(posix.daylight) + fmt.println(posix.timezone) + + Possible Output: + ["CET", "CEST"] + true + -3600 + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tzset.html ]] + */ + tzset :: proc() --- + + // Whether daylight saving conversion should be done. + daylight: b32 + // The time in seconds between UTC and local standard time. + @(link_name=LTIMEZONE) + timezone: c.long + tzname: [2]cstring +} + +time_t :: libc.time_t +clock_t :: libc.clock_t + +tm :: libc.tm +timespec :: libc.timespec + +CLOCKS_PER_SEC :: libc.CLOCKS_PER_SEC + +asctime :: libc.asctime +clock :: libc.clock +ctime :: libc.ctime +difftime :: libc.difftime +gmtime :: libc.gmtime +localtime :: libc.localtime +mktime :: libc.mktime +strftime :: libc.strftime +time :: libc.time + +Clock :: enum clockid_t { + // system-wide monotonic clock, defined as clock measuring real time, + // can be set with clock_settime() and cannot have negative clock jumps. + MONOTONIC = CLOCK_MONOTONIC, + // CPU-time clock associated with the process making a clock() function call. + PROCESS_CPUTIME_ID = CLOCK_PROCESS_CPUTIME_ID, + // system-wide clock measuring real time. + REALTIME = CLOCK_REALTIME, + // CPU-time clock associated with the thread making a clock() function call. + THREAD_CPUTIME_ID = CLOCK_THREAD_CPUTIME_ID, +} + +when ODIN_OS == .NetBSD { + @(private) LCTIMER :: "__ctime_r50" + @(private) LGMTIMER :: "__gmtime_r50" + @(private) LLOCALTIMER :: "__localtime_r50" + @(private) LCLOCKGETRES :: "__clock_getres50" + @(private) LCLOCKGETTIME :: "__clock_gettime50" + @(private) LCLOCKSETTIME :: "__clock_settime50" + @(private) LNANOSLEEP :: "__nanosleep50" + @(private) LTIMEZONE :: "__timezone13" +} else { + @(private) LCTIMER :: "ctime_r" + @(private) LGMTIMER :: "gmtime_r" + @(private) LLOCALTIMER :: "localtime_r" + @(private) LCLOCKGETRES :: "clock_getres" + @(private) LCLOCKGETTIME :: "clock_gettime" + @(private) LCLOCKSETTIME :: "clock_settime" + @(private) LNANOSLEEP :: "nanosleep" + @(private) LTIMEZONE :: "timezone" +} + +when ODIN_OS == .Darwin { + + clockid_t :: distinct c.int + + CLOCK_MONOTONIC :: 6 + CLOCK_PROCESS_CPUTIME_ID :: 12 + CLOCK_REALTIME :: 0 + CLOCK_THREAD_CPUTIME_ID :: 16 + + foreign lib { + getdate_err: Errno + } + +} else when ODIN_OS == .FreeBSD { + + clockid_t :: distinct c.int + + CLOCK_MONOTONIC :: 4 + CLOCK_PROCESS_CPUTIME_ID :: 15 + CLOCK_REALTIME :: 0 + CLOCK_THREAD_CPUTIME_ID :: 14 + + foreign lib { + getdate_err: Errno + } + +} else when ODIN_OS == .NetBSD { + + clockid_t :: distinct c.uint + + CLOCK_MONOTONIC :: 3 + CLOCK_PROCESS_CPUTIME_ID :: 0x40000000 + CLOCK_REALTIME :: 0 + CLOCK_THREAD_CPUTIME_ID :: 0x20000000 + + foreign lib { + getdate_err: Errno + } + +} else when ODIN_OS == .OpenBSD { + + clockid_t :: distinct c.uint + + CLOCK_MONOTONIC :: 3 + CLOCK_PROCESS_CPUTIME_ID :: 2 + CLOCK_REALTIME :: 0 + CLOCK_THREAD_CPUTIME_ID :: 4 + + getdate_err: Errno = .ENOSYS // NOTE: looks like it's not a thing on OpenBSD. + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/ulimit.odin b/core/sys/posix/ulimit.odin new file mode 100644 index 000000000..067b83271 --- /dev/null +++ b/core/sys/posix/ulimit.odin @@ -0,0 +1,43 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// ulimit.h - ulimit commands + +foreign lib { + /* + Control process limits. + + Note that -1 is a valid return value, applications should clear errno, do this call and then + check both -1 and the errno to determine status. + + Returns: -1 (setting errno) on failure. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ulimit.html ]] + */ + ulimit :: proc(i: c.int, #c_vararg arg: ..c.long) -> c.long --- +} + +Ulimit_Cmd :: enum c.int { + // Returns the file size limit of the process in units of 512-byte blocks inherited by children. + GETFSIZE = UL_GETFSIZE, + // Set the file size limit for output operations, taken as a long, multiplied by 512. + SETFSIZE = UL_SETFSIZE, +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + UL_GETFSIZE :: 1 + UL_SETFSIZE :: 2 + + // NOTE: I don't think OpenBSD implements this API. + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/unistd.odin b/core/sys/posix/unistd.odin new file mode 100644 index 000000000..8e08860b4 --- /dev/null +++ b/core/sys/posix/unistd.odin @@ -0,0 +1,1914 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// unistd.h - standard symbolic constants and types + +foreign lib { + /* + Checks the file named by the pathname pointed to by the path argument for + accessibility according to the bit pattern contained in amode. + + Example: + if (posix.access("/tmp/myfile", posix.F_OK) != .OK) { + fmt.printfln("/tmp/myfile access check failed: %v", posix.strerror(posix.errno())) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html ]] + */ + access :: proc(path: cstring, amode: Mode_Flags = F_OK) -> result --- + + /* + Equivalent to `access` but relative paths are resolved based on `fd`. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html ]] + */ + faccessat :: proc(fd: FD, path: cstring, amode: Mode_Flags, flag: AT_Flags) -> result --- + + /* + The alarm() function shall cause the system to generate a SIGALRM signal for the process after the number of realtime seconds specified by seconds have elapsed. Processor scheduling delays may prevent the process from handling the signal as soon as it is generated. + + If seconds is 0, a pending alarm request, if any, is canceled. + + Returns: the time left on the previous alarm() or 0 + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html ]] + */ + alarm :: proc(seconds: c.uint) -> c.uint --- + + /* + Causes the directory named by path to become the current working directory. + + Example: + if (posix.chdir("/tmp") == .OK) { + fmt.println("changed current directory to /tmp") + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html ]] + */ + chdir :: proc(path: cstring) -> result --- + + /* + Equivalent to chdir but instead of a path the fildes is resolved to a directory. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html ]] + */ + fchdir :: proc(fildes: FD) -> result --- + + /* + Changes the user and group ownership of a file. + + If owner or group is specified as (uid_t)-1 or (gid_t)-1, respectively, the corresponding ID of the file shall not be changed. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html ]] + */ + @(link_name=LCHOWN) + chown :: proc(path: cstring, owner: uid_t, group: gid_t) -> result --- + + /* + Equivalent to chown expect that it takes a file descriptor. + + Example: + fildes := posix.open("/home/cnd/mod1", {.RDWR}) + pwd := posix.getpwnam("jones") + grp := posix.getgrnam("cnd") + posix.fchown(fildes, pwd.pw_uid, grp.gr_gid) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html ]] + */ + @(link_name=LFCHOWN) + fchown :: proc(fildes: FD, owner: uid_t, mode: gid_t) -> result --- + + /* + Equivalent to fchown except that relative paths are based on the given fildes. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html ]] + */ + fchownat :: proc(fildes: FD, path: cstring, owner: uid_t, group: gid_t, flag: AT_Flags) -> result --- + + /* + If path points to a symbolic link, the owner and group of the link itself is changed. + Equivalent to chown on normal files. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/lchown.html ]] + */ + @(link_name=LLCHOWN) + lchown :: proc(path: cstring, owner: uid_t, group: gid_t) -> result --- + + /* + Deallocates the file descriptor indicated by fildes. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html ]] + */ + close :: proc(fildes: FD) -> result --- + + /* + Return configuration-defined string values. + Its use and purpose are similar to sysconf(), but it is used where string values rather than numeric values are returned. + + Returns: 0 (setting errno) if `name` is invalid, need `buf` `len` if buf is `nil`, amount of bytes added to buf otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html ]] + */ + confstr :: proc(name: CS, buf: [^]c.char, len: c.size_t) -> c.size_t --- + + /* + Determines the current value of a configurable limit or option that is associated with a file or directory. + + Returns: value on success, -1 (setting errno) on failure, -1 (no errno) if the variable should be taken from limits + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fpathconf.html ]] + */ + pathconf :: proc(path: cstring, name: PC) -> c.long --- + + /* + Equivalent to pathconf but takes a file descriptor instead of a path. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fpathconf.html ]] + */ + fpathconf :: proc(fildes: FD, name: PC) -> c.long --- + + /* + Determines the current value of configurable system limit or options. + + Returns: value on success, -1 (setting errno) on failure, -1 (no errno) if the variable should be taken from limits + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html ]] + */ + sysconf :: proc(name: SC) -> c.long --- + + /* + A string encoding function. The algorithm is implementation-defined. + + The use of crypt() for anything other than password hashing is not recommended. + + Returns: a static string overwritten by subsequent calls, `nil` (setting errno) on failure + */ + crypt :: proc(key: cstring, salt: cstring) -> cstring --- + + /* + An implementation-defined encoding algorithm. + The key generated by setkey() is used to encrypt the string block with encrypt(). + + block must be 64 bytes. + + decode controls if the block is encoded or decoded. + + May set errno to ENOSYS if the functionality is not supported. + + Example: + block: [64]byte + copy(block[:], "Hello, World!") + + posix.set_errno(.NONE) + posix.encrypt(raw_data(block[:]), decode=false) + assert(posix.errno() == .NONE, "encrypt not supported") + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/encrypt.html ]] + */ + encrypt :: proc(block: [^]c.char, decode: b32) --- + + /* + Returns a new file descriptor referring to the one given, sharing locks, clearing CLOEXEC. + + Returns: -1 (setting errno) on failure, the new file descriptor on success + + Example: + // Redirecting stdout to a file: + file := posix.open("/tmp/out", { .RDWR }) + posix.close(1) + posix.dup(file) + posix.close(file) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html ]] + */ + dup :: proc(fildes: FD) -> FD --- + + /* + Causes the file descriptor fildes2 to refer to the same open file description as + the file descriptor fildes and to share any locks, and shall return fildes2. + + Returns: -1 (setting errno) on failure, fildes2 on success + + Example: + // Redirecting stderr to stdout: + posix.dup2(1, 2) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html ]] + */ + dup2 :: proc(fildes, fildes2: FD) -> FD --- + + /* + Exits but, shall not call functions registered with atexit() nor any registered signal handlers. + Open streams shall not be flushed. + Whether open streams are closed (without flushing) is implementation-defined. Finally, the calling process shall be terminated with the consequences described below. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/_exit.html ]] + */ + _exit :: proc(status: c.int) --- + + /* + The exec family of functions shall replace the current process image with a new process image. + The new image shall be constructed from a regular, executable file called the new process image file. + There shall be no return from a successful exec, + because the calling process image is overlaid by the new process image. + + Takes arguments as varargs and the last of them must be nil. + + Example: + ret := posix.execl("/bin/ls", "ls", "-l", nil) + fmt.panicf("could not execute: %v %v", ret, posix.strerror(posix.errno())) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/execl.html ]] + */ + execl :: proc(path: cstring, arg0: cstring, #c_vararg args: ..cstring) -> c.int --- + + /* + The exec family of functions shall replace the current process image with a new process image. + The new image shall be constructed from a regular, executable file called the new process image file. + There shall be no return from a successful exec, + because the calling process image is overlaid by the new process image. + + Takes arguments as varargs and the last of them must be nil. + After the arguments an array of environment strings (also nil terminated) is expected. + + Example: + env := []cstring{ + "HOME=/usr/home", + "LOGNAME=home", + nil, + } + ret := posix.execle("/bin/ls", "ls", cstring("-l"), cstring(nil), raw_data(env)) + fmt.panicf("could not execute: %v", posix.strerror(posix.errno())) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/execl.html ]] + */ + execle :: proc(path: cstring, arg0: cstring, #c_vararg args: ..any) -> c.int --- + + /* + The exec family of functions shall replace the current process image with a new process image. + The new image shall be constructed from a regular, executable file called the new process image file. + There shall be no return from a successful exec, + because the calling process image is overlaid by the new process image. + + If file does not contain a slash the PATH environment variable is searched for a matching file. + Takes arguments as varargs and the last of them must be nil. + + Example: + ret := posix.execlp("ls", "-l", cstring(nil)) + fmt.panicf("could not execute: %v, %v", ret, posix.strerror(posix.errno())) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/execl.html ]] + */ + execlp :: proc(file: cstring, arg0: cstring, #c_vararg args: ..cstring) -> c.int --- + + /* + The exec family of functions shall replace the current process image with a new process image. + The new image shall be constructed from a regular, executable file called the new process image file. + There shall be no return from a successful exec, + because the calling process image is overlaid by the new process image. + + Takes arguments as an array which should be nil terminated. + + Example: + args := []cstring{ "ls", "-l", nil } + ret := posix.execv("/bin/ls", raw_data(args)) + fmt.panicf("could not execute: %v, %v", ret, posix.strerror(posix.errno())) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/execl.html ]] + */ + execv :: proc(path: cstring, argv: [^]cstring) -> c.int --- + + /* + The exec family of functions shall replace the current process image with a new process image. + The new image shall be constructed from a regular, executable file called the new process image file. + There shall be no return from a successful exec, + because the calling process image is overlaid by the new process image. + + If file does not contain a slash the PATH environment variable is searched for a matching file. + Takes arguments as an array which should be nil terminated. + + Example: + cmd := []cstring{ "ls", "-l", nil } + ret := posix.execvp("ls", raw_data(cmd)) + fmt.panicf("could not execute: %v, %v", ret, posix.strerror(posix.errno())) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/execl.html ]] + */ + execvp :: proc(file: cstring, argv: [^]cstring) -> c.int --- + + /* + The exec family of functions shall replace the current process image with a new process image. + The new image shall be constructed from a regular, executable file called the new process image file. + There shall be no return from a successful exec, + because the calling process image is overlaid by the new process image. + + Takes arguments as an array which should be nil terminated. + Takes environment variables as an array which should be nil terminated. + + Example: + cmd := []cstring{ "ls", "-l", nil } + env := []cstring{ "HOME=/usr/home", "LOGNAME=home", nil } + ret := posix.execve("/bin/ls", raw_data(cmd), raw_data(env)) + fmt.panicf("could not execute: %v, %v", ret, posix.strerror(posix.errno())) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/execl.html ]] + */ + execve :: proc(path: cstring, argv: [^]cstring, envp: [^]cstring) -> c.int --- + + /* + The exec family of functions shall replace the current process image with a new process image. + The new image shall be constructed from a regular, executable file called the new process image file. + There shall be no return from a successful exec, + because the calling process image is overlaid by the new process image. + + Equivalent to execve but takes a file descriptor instead of a path. + + Example: + ls := posix.open("/bin/ls", { .EXEC }) + cmd := []cstring{ "ls", "-l", nil } + env := []cstring{ "HOME=/usr/home", "LOGNAME=home", nil } + ret := posix.fexecve(ls, raw_data(cmd), raw_data(env)) + fmt.panicf("could not execute: %v, %v", ret, posix.strerror(posix.errno())) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/execl.html ]] + */ + fexecve :: proc(fd: FD, argv: [^]cstring, envp: [^]cstring) -> c.int --- + + /* + Example: + for i, entry := 0, posix.environ[0]; entry != nil; i, entry = i+1, posix.environ[i] { + fmt.println(entry) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/execl.html ]] + */ + environ: [^]cstring + + /* + Forcec all currently queued I/O operations associated with the file indicated by file descriptor + fildes to the synchronized I/O completion state. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html ]] + */ + fdatasync :: proc(fd: FD) -> result --- + + /* + The fork() function shall create a new process. + The new process (child process) shall be an exact copy of the calling process (parent process). + With some exceptions outlined below. + + Result: -1 (setting errno) on failure, otherwise 0 to the child process and the child process id to the parent process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html ]] + */ + fork :: proc() -> pid_t --- + + /* + Requests that all data for the open file descriptor named by fildes is to be transferred + to the storage device associated with the file described by fildes. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html ]] + */ + fsync :: proc(fildes: FD) -> result --- + + /* + Truncates a file to the specified length. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html ]] + */ + truncate :: proc(path: cstring, length: off_t) -> result --- + + /* + Truncates a file to the specified length. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html ]] + */ + ftruncate :: proc(fildes: FD, length: off_t) -> result --- + + /* + Places an absolute pathname of the current working directory into buf. + + Returns: buf as a cstring on success, nil (setting errno) on failure + + Example: + size: int + path_max := posix.pathconf(".", ._PATH_MAX) + if path_max == -1 { + size = 1024 + } else if path_max > 10240 { + size = 10240 + } else { + size = int(path_max) + } + + buf: [dynamic]byte + cwd: cstring + for ; cwd == nil; size *= 2 { + if err := resize(&buf, size); err != nil { + fmt.panicf("allocation failure: %v", err) + } + + cwd = posix.getcwd(raw_data(buf), len(buf)) + if errno := posix.errno(); cwd == nil && errno != .ERANGE { + fmt.panicf("getcwd failure: %v", posix.strerror(errno)) + } + } + + fmt.println(path_max, cwd) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html ]] + */ + getcwd :: proc(buf: [^]c.char, size: c.size_t) -> cstring --- + + /* + Returns the effective group ID of the calling process. + + Returns: the ID, no failure is defined + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html ]] + */ + getegid :: proc() -> gid_t --- + + /* + Returns the effective user ID of the calling process. + + Returns: the ID, no failure is defined + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html ]] + */ + geteuid :: proc() -> uid_t --- + + /* + Returns the real group ID of the calling process. + + Returns: the ID, no failure is defined + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html ]] + */ + getgid :: proc() -> gid_t --- + + /* + Fills the grouplist array with the current supplementary group IDs of the calling process. + + Returns: -1 (setting errno) on failure, desired grouplist length if gidsetsize is 0, amount of IDs added otherwise + + Example: + length := posix.getgroups(0, nil) + if length == -1 { + fmt.panicf("getgroups failure: %v", posix.strerror(posix.errno())) + } + + groups := make([]posix.gid_t, length) or_else panic("allocation failure") + if posix.getgroups(length, raw_data(groups)) != length { + fmt.panicf("getgroups failure: %v", posix.strerror(posix.errno())) + } + + fmt.println(groups) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgroups.html ]] + */ + getgroups :: proc(gidsetsize: c.int, grouplist: [^]gid_t) -> c.int --- + + /* + Retrieves a 32-bit identifier for the current host. + + Returns: the ID, no failure is defined + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostid.html ]] + */ + gethostid :: proc() -> c.long --- + + /* + Returns the standard host name for the current machine. + + Host names are limited to HOST_NAME_MAX bytes. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html ]] + */ + gethostname :: proc(name: [^]c.char, namelen: c.size_t) -> result --- + + /* + Returns a string containing the user name associated by the login activity. + + Returns: nil (setting errno) on failure, the login name otherwise in a potentially static buffer overwritten by subsequent calls + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getlogin.html ]] + */ + getlogin :: proc() -> cstring --- + + /* + Equivalent to getlogin but puts the name in the name buffer given. + + The name is limited to LOGIN_NAME_MAX bytes. + + Example: + max := posix.sysconf(posix._SC_LOGIN_NAME_MAX)+1 + buf := make([]byte, max) + posix.getlogin_r(raw_data(buf), uint(len(max))) + fmt.printfln("login: %v", cstring(buf)) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getlogin.html ]] + */ + getlogin_r :: proc(name: [^]c.char, namelen: c.size_t) -> Errno --- + + /* + A command-line parser, see linked docs. + + Example: + // The following code fragment shows how you might process the arguments for a utility that + // can take the mutually-exclusive options a and b and the options f and o, both of which + // require arguments. + + bflg, aflg, errflg: bool + ifile: string + ofile: string + + for { + c := posix.getopt(i32(len(runtime.args__)), raw_data(runtime.args__), ":abf:o:") + (c != -1) or_break + + switch c { + case 'a': + if bflg { + errflg = true + } else { + aflg = true + } + case 'b': + if aflg { + errflg = true + } else { + bflg = true + } + case 'f': + ifile = string(posix.optarg) + case 'o': + ofile = string(posix.optarg) + case ':': /* -f or -o without operand */ + fmt.eprintfln("Option -%c requires an operand", posix.optopt) + errflg = true + case '?': + fmt.eprintfln("Unrecognized option: '-%c'", posix.optopt) + errflg = true + } + } + + if errflg { + fmt.eprintfln("usage: . . . ") + posix.exit(2) + } + + // Loop through remaining arguments: + for ; posix.optind < i32(len(runtime.args__)); posix.optind += 1 { + fmt.println(runtime.args__[posix.optind]) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html ]] + */ + getopt :: proc(argc: c.int, argv: [^]cstring, optstring: cstring) -> c.int --- + + optarg: cstring + opterr: c.int + optind: c.int + optopt: c.int + + /* + Returns the process group ID of the process whose process ID is equal to pid. + If pid is 0, it returns the process group ID of the calling process. + + Returns: -1 on failure, the ID otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgid.html ]] + */ + getpgid :: proc(pid: pid_t) -> pid_t --- + + /* + Returns the process group ID of the calling process. + + Returns: no failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html ]] + */ + getpgrp :: proc() -> pid_t --- + + /* + Returns the ID of the calling process. + + Returns: no failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html ]] + */ + getpid :: proc() -> pid_t --- + + /* + Returns the parent process ID. + + Returns: no failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html ]] + */ + getppid :: proc() -> pid_t --- + + + /* + Get the process group ID of the session leader. + If pid is 0, it is the current process. + + Returns: -1 (setting errno) on failure, the pid otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html ]] + */ + getsid :: proc(pid: pid_t) -> pid_t --- + + /* + Returns the real user ID of the calling process. + + Returns: no failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html ]] + */ + getuid :: proc() -> uid_t --- + + /* + Tests whether fildes is associated with a terminal device. + + Returns: false (setting errno) if fildes is invalid or not a terminal, true otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/isatty.html ]] + */ + isatty :: proc(fildes: FD) -> b32 --- + + /* + Creates a new link for the existing file path1 to path2. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html ]] + */ + link :: proc(path1: cstring, path2: cstring) -> result --- + + /* + If path1 is relative it is relative to directory fd1. + If path2 is relative it is relative to directory fd2. + If flag is { .SYMLINK_FOLLOW } path1 is resolved to its link if it is a link. + Equivalent to link otherwise. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/link.html ]] + */ + linkat :: proc(fd1: FD, path1: cstring, fd2: FD, path2: cstring, flag: AT_Flags) -> result --- + + /* + Creates a symbolic link called path2 that contains a link to path1. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlink.html ]] + */ + symlink :: proc(path1: cstring, path2: cstring) -> result --- + + /* + Equivalent to symlink but relative paths are resolved to dir fd. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlink.html ]] + */ + symlinkat :: proc(path1: cstring, fd: FD, path2: cstring) -> result --- + + /* + Locks sections of a file with advisory-mode locks. + + Example: + fildes := posix.open("/home/cnd/mod1", { .RDWR }) + if posix.lockf(fildes, .TLOCK, 10000) != .OK { + errno := posix.errno(); #partial switch errno { + case .EACCES, .EAGAIN: + // File is already locked. + case: + // Other error. + fmt.panicf("lockf failure: %v", posix.strerror(errno)) + } + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/lockf.html ]] + */ + lockf :: proc(fildes: FD, function: Lock_Function, size: off_t) -> result --- + + /* + Sets the file offset of the given file descriptor. + + If whence is .SET, the offset is set + If whence is .CUR, the offset is the current offset + given offset + If whence is .END, the offset is set to the size of the file + given offset + + Returns: the resulting offset or -1 (setting errno) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html ]] + */ + lseek :: proc(fildes: FD, offset: off_t, whence: Whence) -> off_t --- + + /* + Changes the nice value of a process. + + Higher values result in less favorable scheduling. + + Because -1 is a valid nice value, checking failure would be done by first setting errno to .NONE + and then calling nice. + + Returns: the new nice value, or -1 (setting) errno on failure + + Example: + posix.set_errno(.NONE) + niceness := posix.nice(-20) + if errno := posix.errno(); niceness == -1 && errno != .NONE { + fmt.panicf("nice failure: %v", posix.strerror(errno)) + } + fmt.printfln("Niceness is now: %v", niceness) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/nice.html ]] + */ + nice :: proc(incr: c.int) -> c.int --- + + /* + Suspend the thread until a signal is received. + + Returns: -1 (setting errno to EINTR) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html ]] + */ + pause :: proc() -> c.int --- + + /* + Create an interprocess channel. + + Example: + fildes: [2]posix.FD + if posix.pipe(&fildes) != .OK { + // Handle error ... + } + + switch posix.fork() { + case -1: + // Handle error ... + + case 0: /* Child - reads from pipe */ + BSIZE :: 100 + buf: [BSIZE]byte + nbytes: int + + posix.close(fildes[1]) /* Write end is unused */ + nbytes = posix.read(fildes[0], raw_data(buf[:]), BSIZE) /* Get data from pipe */ + /* At this point, a further read would see end-of-file ... */ + posix.close(fildes[0]) /* Finished with pipe */ + + fmt.println(string(buf[:nbytes])) + + posix.exit(0) + + case: /* Parent - write to pipe */ + msg := raw_data(transmute([]byte)string("Hello world\n")) + posix.close(fildes[0]) /* Read end is unused */ + posix.write(fildes[1], msg, 12); /* Write data on pipe */ + posix.close(fildes[1]) + posix.exit(0) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html ]] + */ + pipe :: proc(fildes: ^[2]FD) -> result --- + + /* + Read from a file. + + Returns: the amount of bytes read or -1 (setting errno) on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html ]] + */ + read :: proc(fd: FD, buf: [^]byte, nbyte: c.size_t) -> c.ssize_t --- + + /* + Equivalent to read on a specified offset instead of the internal offset. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html ]] + */ + pread :: proc(fd: FD, buf: [^]byte, nbyte: c.size_t, offset: off_t) -> c.ssize_t --- + + /* + Write on a file. + + Returns: the amount of bytes written or -1 (setting errno) on failure. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html ]] + */ + write :: proc(fd: FD, buf: [^]byte, buflen: c.size_t) -> c.ssize_t --- + + /* + Equivalent to write on a specified offset instead of the internal offset. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html ]] + */ + pwrite :: proc(fd: FD, buf: [^]byte, buflen: c.size_t, offset: off_t) -> c.ssize_t --- + + /* + Read the contents of a symbolic link. + + Returns: the amount of bytes read or -1 (setting errno) on failure. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html ]] + */ + readlink :: proc(path: cstring, buf: [^]byte, bufsize: c.size_t) -> c.ssize_t --- + + /* + Equivalent to readlink but relative paths are resolved based on the dir fd. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/readlink.html ]] + */ + readlinkat :: proc(fd: FD, path: cstring, buf: [^]byte, bufsize: c.size_t) -> c.ssize_t --- + + /* + Remove an (empty) directory. + + ]] More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html ]] + */ + rmdir :: proc(path: cstring) -> result --- + + /* + Set the effective group ID. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html ]] + */ + setegid :: proc(gid: gid_t) -> result --- + + /* + Sets the effective user ID. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html ]] + */ + seteuid :: proc(uid: uid_t) -> result --- + + /* + Sets the group ID. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html ]] + */ + setgid :: proc(gid: gid_t) -> result --- + + /* + Set process group ID. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html ]] + */ + setpgid :: proc(pid: pid_t, pgid: pid_t) -> result --- + + /* + Set the process group ID to that of the process. + + Returns: the process group id, no failures are defined + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgrp.html ]] + */ + setpgrp :: proc() -> pid_t --- + + /* + Set the real and effective group IDs. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setregid.html ]] + */ + setregid :: proc(rgid: gid_t, egid: gid_t) -> result --- + + /* + Set real and effective user IDs. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setreuid.html ]] + */ + setreuid :: proc(ruid: uid_t, euid: uid_t) -> result --- + + /* + Create session and set process group ID. + + Returns: the new process group ID or -1 (setting errno) on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html ]] + */ + setsid :: proc() -> pid_t --- + + /* + Set user ID. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html ]] + */ + setuid :: proc(uid: uid_t) -> result --- + + /* + Suspend execution for an interval of time. + + Returns: the time left to sleep (may be > 0 in case of signals) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sleep.html ]] + */ + sleep :: proc(seconds: c.uint) -> c.uint --- + + /* + Copy nbyte bytes, from src, to dest, exchanging adjecent bytes. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/swab.html ]] + */ + swab :: proc(src: [^]byte, dest: [^]byte, nbytes: c.ssize_t) --- + + /* + Schedule file system updates. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html ]] + */ + sync :: proc() --- + + /* + Get the foreground process group ID. + + Returns: -1 (setting errno) on failure, the id otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html ]] + */ + tcgetpgrp :: proc(fildes: FD) -> pid_t --- + + /* + Set the foreground process group ID. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html ]] + */ + tcsetpgrp :: proc(fildes: FD, pgid_id: pid_t) -> result --- + + /* + Find the path name of a terminal. + + Returns: nil (setting errno) on failure, the name, which may be invalidated by subsequent calls on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ttyname.html ]] + */ + ttyname :: proc(fildes: FD) -> cstring --- + + /* + Equivalent to ttyname but name is placed into the buf. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/ttyname.html ]] + */ + ttyname_r :: proc(fildes: FD, name: [^]byte, namesize: c.size_t) -> Errno --- + + /* + Remove a directory entry. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html ]] + */ + unlink :: proc(path: cstring) -> result --- + + /* + Equivalent to unlink or rmdir (if flag is .REMOVEDIR) but relative paths are relative to the dir fd. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html ]] + */ + unlinkat :: proc(fd: FD, path: cstring, flag: AT_Flags) -> result --- +} + +STDERR_FILENO :: 2 +STDIN_FILENO :: 0 +STDOUT_FILENO :: 1 + +Mode_Flag_Bits :: enum c.int { + X_OK = log2(X_OK), + W_OK = log2(W_OK), + R_OK = log2(R_OK), +} +Mode_Flags :: bit_set[Mode_Flag_Bits; c.int] + +#assert(_F_OK == 0) +F_OK :: Mode_Flags{} + +CS :: enum c.int { + _PATH = _CS_PATH, + _POSIX_V6_ILP32_OFF32_CFLAGS = _CS_POSIX_V6_ILP32_OFF32_CFLAGS, + _POSIX_V6_ILP32_OFF32_LDFLAGS = _CS_POSIX_V6_ILP32_OFF32_LDFLAGS, + _POSIX_V6_ILP32_OFF32_LIBS = _CS_POSIX_V6_ILP32_OFF32_LIBS, + _POSIX_V6_ILP32_OFFBIG_CFLAGS = _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS, + _POSIX_V6_ILP32_OFFBIG_LDFLAGS = _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS, + _POSIX_V6_ILP32_OFFBIG_LIBS = _CS_POSIX_V6_ILP32_OFFBIG_LIBS, + _POSIX_V6_LP64_OFF64_CFLAGS = _CS_POSIX_V6_LP64_OFF64_CFLAGS, + _POSIX_V6_LP64_OFF64_LDFLAGS = _CS_POSIX_V6_LP64_OFF64_LDFLAGS, + _POSIX_V6_LP64_OFF64_LIBS = _CS_POSIX_V6_LP64_OFF64_LIBS, + _POSIX_V6_LPBIG_OFFBIG_CFLAGS = _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS, + _POSIX_V6_LPBIG_OFFBIG_LDFLAGS = _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS, + _POSIX_V6_LPBIG_OFFBIG_LIBS = _CS_POSIX_V6_LPBIG_OFFBIG_LIBS, + _POSIX_V6_WIDTH_RESTRICTED_ENVS = _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS, +} + +PC :: enum c.int { + _2_SYMLINK = _PC_2_SYMLINK, + _ALLOC_SIZE_MIN = _PC_ALLOC_SIZE_MIN, + _ASYNC_IO = _PC_ASYNC_IO, + _CHOWN_RESTRICTED = _PC_CHOWN_RESTRICTED, + _FILESIZEBITS = _PC_FILESIZEBITS, + _LINK_MAX = _PC_LINK_MAX, + _MAX_CANON = _PC_MAX_CANON, + _MAX_INPUT = _PC_MAX_INPUT, + _NAME_MAX = _PC_NAME_MAX, + _NO_TRUNC = _PC_NO_TRUNC, + _PATH_MAX = _PC_PATH_MAX, + _PIPE_BUF = _PC_PIPE_BUF, + _PRIO_IO = _PC_PRIO_IO, + _REC_INCR_XFER_SIZE = _PC_REC_INCR_XFER_SIZE, + _REC_MAX_XFER_SIZE = _PC_REC_MAX_XFER_SIZE, + _REC_MIN_XFER_SIZE = _PC_REC_MIN_XFER_SIZE, + _REC_XFER_ALIGN = _PC_REC_XFER_ALIGN, + _SYMLINK_MAX = _PC_SYMLINK_MAX, + _SYNC_IO = _PC_SYNC_IO, + _VDISABLE = _PC_VDISABLE, +} + +SC :: enum c.int { + _2_C_BIND = _SC_2_C_BIND, + _2_C_DEV = _SC_2_C_DEV, + _2_CHAR_TERM = _SC_2_CHAR_TERM, + _2_FORT_DEV = _SC_2_FORT_DEV, + _2_FORT_RUN = _SC_2_FORT_RUN, + _2_LOCALEDEF = _SC_2_LOCALEDEF, + _2_PBS = _SC_2_PBS, + _2_PBS_ACCOUNTING = _SC_2_PBS_ACCOUNTING, + _2_PBS_CHECKPOINT = _SC_2_PBS_CHECKPOINT, + _2_PBS_LOCATE = _SC_2_PBS_LOCATE, + _2_PBS_MESSAGE = _SC_2_PBS_MESSAGE, + _2_PBS_TRACK = _SC_2_PBS_TRACK, + _2_SW_DEV = _SC_2_SW_DEV, + _2_UPE = _SC_2_UPE, + _2_VERSION = _SC_2_VERSION, + _ADVISORY_INFO = _SC_ADVISORY_INFO, + _AIO_LISTIO_MAX = _SC_AIO_LISTIO_MAX, + _AIO_MAX = _SC_AIO_MAX, + _AIO_PRIO_DELTA_MAX = _SC_AIO_PRIO_DELTA_MAX, + _ARG_MAX = _SC_ARG_MAX, + _ASYNCHRONOUS_IO = _SC_ASYNCHRONOUS_IO, + _ATEXIT_MAX = _SC_ATEXIT_MAX, + _BARRIERS = _SC_BARRIERS, + _BC_BASE_MAX = _SC_BC_BASE_MAX, + _BC_DIM_MAX = _SC_BC_DIM_MAX, + _BC_SCALE_MAX = _SC_BC_SCALE_MAX, + _BC_STRING_MAX = _SC_BC_STRING_MAX, + _CHILD_MAX = _SC_CHILD_MAX, + _CLK_TCK = _SC_CLK_TCK, + _CLOCK_SELECTION = _SC_CLOCK_SELECTION, + _COLL_WEIGHTS_MAX = _SC_COLL_WEIGHTS_MAX, + _CPUTIME = _SC_CPUTIME, + _DELAYTIMER_MAX = _SC_DELAYTIMER_MAX, + _EXPR_NEST_MAX = _SC_EXPR_NEST_MAX, + _FSYNC = _SC_FSYNC, + _GETGR_R_SIZE_MAX = _SC_GETGR_R_SIZE_MAX, + _GETPW_R_SIZE_MAX = _SC_GETPW_R_SIZE_MAX, + _HOST_NAME_MAX = _SC_HOST_NAME_MAX, + _IOV_MAX = _SC_IOV_MAX, + _IPV6 = _SC_IPV6, + _JOB_CONTROL = _SC_JOB_CONTROL, + _LINE_MAX = _SC_LINE_MAX, + _LOGIN_NAME_MAX = _SC_LOGIN_NAME_MAX, + _MAPPED_FILES = _SC_MAPPED_FILES, + _MEMLOCK = _SC_MEMLOCK, + _MEMLOCK_RANGE = _SC_MEMLOCK_RANGE, + _MEMORY_PROTECTION = _SC_MEMORY_PROTECTION, + _MESSAGE_PASSING = _SC_MESSAGE_PASSING, + _MONOTONIC_CLOCK = _SC_MONOTONIC_CLOCK, + _MQ_OPEN_MAX = _SC_MQ_OPEN_MAX, + _MQ_PRIO_MAX = _SC_MQ_PRIO_MAX, + _NGROUPS_MAX = _SC_NGROUPS_MAX, + _OPEN_MAX = _SC_OPEN_MAX, + _PAGE_SIZE = _SC_PAGE_SIZE, + _PAGESIZE = _SC_PAGESIZE, + _PRIORITIZED_IO = _SC_PRIORITIZED_IO, + _PRIORITY_SCHEDULING = _SC_PRIORITY_SCHEDULING, + _RAW_SOCKETS = _SC_RAW_SOCKETS, + _RE_DUP_MAX = _SC_RE_DUP_MAX, + _READER_WRITER_LOCKS = _SC_READER_WRITER_LOCKS, + _REALTIME_SIGNALS = _SC_REALTIME_SIGNALS, + _REGEXP = _SC_REGEXP, + _RTSIG_MAX = _SC_RTSIG_MAX, + _SAVED_IDS = _SC_SAVED_IDS, + _SEM_NSEMS_MAX = _SC_SEM_NSEMS_MAX, + _SEM_VALUE_MAX = _SC_SEM_VALUE_MAX, + _SEMAPHORES = _SC_SEMAPHORES, + _SHARED_MEMORY_OBJECTS = _SC_SHARED_MEMORY_OBJECTS, + _SHELL = _SC_SHELL, + _SIGQUEUE_MAX = _SC_SIGQUEUE_MAX, + _SPAWN = _SC_SPAWN, + _SPIN_LOCKS = _SC_SPIN_LOCKS, + _SPORADIC_SERVER = _SC_SPORADIC_SERVER, + _SS_REPL_MAX = _SC_SS_REPL_MAX, + _STREAM_MAX = _SC_STREAM_MAX, + _SYMLOOP_MAX = _SC_SYMLOOP_MAX, + _SYNCHRONIZED_IO = _SC_SYNCHRONIZED_IO, + _THREAD_ATTR_STACKADDR = _SC_THREAD_ATTR_STACKADDR, + _THREAD_ATTR_STACKSIZE = _SC_THREAD_ATTR_STACKSIZE, + _THREAD_CPUTIME = _SC_THREAD_CPUTIME, + _THREAD_DESTRUCTOR_ITERATIONS = _SC_THREAD_DESTRUCTOR_ITERATIONS, + _THREAD_KEYS_MAX = _SC_THREAD_KEYS_MAX, + _THREAD_PRIO_INHERIT = _SC_THREAD_PRIO_INHERIT, + _THREAD_PRIO_PROTECT = _SC_THREAD_PRIO_PROTECT, + _THREAD_PRIORITY_SCHEDULING = _SC_THREAD_PRIORITY_SCHEDULING, + _THREAD_PROCESS_SHARED = _SC_THREAD_PROCESS_SHARED, + _THREAD_SAFE_FUNCTIONS = _SC_THREAD_SAFE_FUNCTIONS, + _THREAD_SPORADIC_SERVER = _SC_THREAD_SPORADIC_SERVER, + _THREAD_STACK_MIN = _SC_THREAD_STACK_MIN, + _THREAD_THREADS_MAX = _SC_THREAD_THREADS_MAX, + _THREADS = _SC_THREADS, + _TIMEOUTS = _SC_TIMEOUTS, + _TIMER_MAX = _SC_TIMER_MAX, + _TIMERS = _SC_TIMERS, + _TRACE = _SC_TRACE, + _TRACE_EVENT_FILTER = _SC_TRACE_EVENT_FILTER, + _TRACE_EVENT_NAME_MAX = _SC_TRACE_EVENT_NAME_MAX, + _TRACE_INHERIT = _SC_TRACE_INHERIT, + _TRACE_LOG = _SC_TRACE_LOG, + _TRACE_NAME_MAX = _SC_TRACE_NAME_MAX, + _TRACE_SYS_MAX = _SC_TRACE_SYS_MAX, + _TRACE_USER_EVENT_MAX = _SC_TRACE_USER_EVENT_MAX, + _TTY_NAME_MAX = _SC_TTY_NAME_MAX, + _TYPED_MEMORY_OBJECTS = _SC_TYPED_MEMORY_OBJECTS, + _TZNAME_MAX = _SC_TZNAME_MAX, + _V6_ILP32_OFF32 = _SC_V6_ILP32_OFF32, + _V6_ILP32_OFFBIG = _SC_V6_ILP32_OFFBIG, + _V6_LP64_OFF64 = _SC_V6_LP64_OFF64, + _V6_LPBIG_OFFBIG = _SC_V6_LPBIG_OFFBIG, + _VERSION = _SC_VERSION, + _XOPEN_CRYPT = _SC_XOPEN_CRYPT, + _XOPEN_ENH_I18N = _SC_XOPEN_ENH_I18N, + _XOPEN_REALTIME = _SC_XOPEN_REALTIME, + _XOPEN_REALTIME_THREADS = _SC_XOPEN_REALTIME_THREADS, + _XOPEN_SHM = _SC_XOPEN_SHM, + _XOPEN_STREAMS = _SC_XOPEN_STREAMS, + _XOPEN_UNIX = _SC_XOPEN_UNIX, + _XOPEN_VERSION = _SC_XOPEN_VERSION, +} + +Lock_Function :: enum c.int { + // Lock a section for exclusive use. + LOCK = F_LOCK, + // Test a section for locks by other processes. + TEST = F_TEST, + // Test and lock a section for exclusive use. + TLOCK = F_TLOCK, + // Unlock locked sections. + ULOCK = F_ULOCK, +} + +when ODIN_OS == .NetBSD { + @(private) LCHOWN :: "__posix_chown" + @(private) LFCHOWN :: "__posix_fchown" + @(private) LLCHOWN :: "__posix_lchown" +} else { + @(private) LCHOWN :: "chown" + @(private) LFCHOWN :: "fchown" + @(private) LLCHOWN :: "lchown" +} + +when ODIN_OS == .Darwin { + + _F_OK :: 0 + X_OK :: (1<<0) + W_OK :: (1<<1) + R_OK :: (1<<2) + + F_LOCK :: 1 + F_TEST :: 3 + F_TLOCK :: 2 + F_ULOCK :: 0 + + _CS_PATH :: 1 + _CS_POSIX_V6_ILP32_OFF32_CFLAGS :: 2 + _CS_POSIX_V6_ILP32_OFF32_LDFLAGS :: 3 + _CS_POSIX_V6_ILP32_OFF32_LIBS :: 4 + _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS :: 5 + _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS :: 6 + _CS_POSIX_V6_ILP32_OFFBIG_LIBS :: 7 + _CS_POSIX_V6_LP64_OFF64_CFLAGS :: 8 + _CS_POSIX_V6_LP64_OFF64_LDFLAGS :: 9 + _CS_POSIX_V6_LP64_OFF64_LIBS :: 10 + _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS :: 11 + _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS :: 12 + _CS_POSIX_V6_LPBIG_OFFBIG_LIBS :: 13 + _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS :: 14 + + _PC_LINK_MAX :: 1 + _PC_MAX_CANON :: 2 + _PC_MAX_INPUT :: 3 + _PC_NAME_MAX :: 4 + _PC_PATH_MAX :: 5 + _PC_PIPE_BUF :: 6 + _PC_CHOWN_RESTRICTED :: 7 + _PC_NO_TRUNC :: 8 + _PC_VDISABLE :: 9 + _PC_2_SYMLINK :: 15 + _PC_ALLOC_SIZE_MIN :: 16 + _PC_ASYNC_IO :: 17 + _PC_FILESIZEBITS :: 18 + _PC_PRIO_IO :: 19 + _PC_REC_INCR_XFER_SIZE :: 20 + _PC_REC_MAX_XFER_SIZE :: 21 + _PC_REC_MIN_XFER_SIZE :: 22 + _PC_REC_XFER_ALIGN :: 23 + _PC_SYMLINK_MAX :: 24 + _PC_SYNC_IO :: 25 + + _SC_ARG_MAX :: 1 + _SC_CHILD_MAX :: 2 + _SC_CLK_TCK :: 3 + _SC_NGROUPS_MAX :: 4 + _SC_OPEN_MAX :: 5 + _SC_JOB_CONTROL :: 6 + _SC_SAVED_IDS :: 7 + _SC_VERSION :: 8 + _SC_BC_BASE_MAX :: 9 + + _SC_BC_DIM_MAX :: 10 + _SC_BC_SCALE_MAX :: 11 + _SC_BC_STRING_MAX :: 12 + _SC_COLL_WEIGHTS_MAX :: 13 + _SC_EXPR_NEST_MAX :: 14 + _SC_LINE_MAX :: 15 + _SC_RE_DUP_MAX :: 16 + _SC_2_VERSION :: 17 + _SC_2_C_BIND :: 18 + _SC_2_C_DEV :: 19 + + _SC_2_CHAR_TERM :: 20 + _SC_2_FORT_DEV :: 21 + _SC_2_FORT_RUN :: 22 + _SC_2_LOCALEDEF :: 23 + _SC_2_SW_DEV :: 24 + _SC_2_UPE :: 25 + _SC_STREAM_MAX :: 26 + _SC_TZNAME_MAX :: 27 + _SC_ASYNCHRONOUS_IO :: 28 + _SC_PAGE_SIZE :: 29 + _SC_PAGESIZE :: _SC_PAGE_SIZE + + _SC_MEMLOCK :: 30 + _SC_MEMLOCK_RANGE :: 31 + _SC_MEMORY_PROTECTION :: 32 + _SC_MESSAGE_PASSING :: 33 + _SC_PRIORITIZED_IO :: 34 + _SC_PRIORITY_SCHEDULING :: 35 + _SC_REALTIME_SIGNALS :: 36 + _SC_SEMAPHORES :: 37 + _SC_FSYNC :: 38 + _SC_SHARED_MEMORY_OBJECTS :: 39 + + _SC_SYNCHRONIZED_IO :: 40 + _SC_TIMERS :: 41 + _SC_AIO_LISTIO_MAX :: 42 + _SC_AIO_MAX :: 43 + _SC_AIO_PRIO_DELTA_MAX :: 44 + _SC_DELAYTIMER_MAX :: 45 + _SC_MQ_OPEN_MAX :: 46 + _SC_MAPPED_FILES :: 47 + _SC_RTSIG_MAX :: 48 + _SC_SEM_NSEMS_MAX :: 49 + + _SC_SEM_VALUE_MAX :: 50 + _SC_SIGQUEUE_MAX :: 51 + _SC_TIMER_MAX :: 52 + _SC_IOV_MAX :: 56 + _SC_2_PBS :: 59 + + _SC_2_PBS_ACCOUNTING :: 60 + _SC_2_PBS_CHECKPOINT :: 61 + _SC_2_PBS_LOCATE :: 62 + _SC_2_PBS_MESSAGE :: 63 + _SC_2_PBS_TRACK :: 64 + _SC_ADVISORY_INFO :: 65 + _SC_BARRIERS :: 66 + _SC_CLOCK_SELECTION :: 67 + _SC_CPUTIME :: 68 + + _SC_GETGR_R_SIZE_MAX :: 70 + _SC_GETPW_R_SIZE_MAX :: 71 + _SC_HOST_NAME_MAX :: 72 + _SC_LOGIN_NAME_MAX :: 73 + _SC_MONOTONIC_CLOCK :: 74 + _SC_MQ_PRIO_MAX :: 75 + _SC_READER_WRITER_LOCKS :: 76 + _SC_REGEXP :: 77 + _SC_SHELL :: 78 + _SC_SPAWN :: 79 + + _SC_SPIN_LOCKS :: 80 + _SC_SPORADIC_SERVER :: 81 + _SC_THREAD_ATTR_STACKADDR :: 82 + _SC_THREAD_ATTR_STACKSIZE :: 83 + _SC_THREAD_CPUTIME :: 84 + _SC_THREAD_DESTRUCTOR_ITERATIONS :: 85 + _SC_THREAD_KEYS_MAX :: 86 + _SC_THREAD_PRIO_INHERIT :: 87 + _SC_THREAD_PRIO_PROTECT :: 88 + _SC_THREAD_PRIORITY_SCHEDULING :: 89 + + _SC_THREAD_PROCESS_SHARED :: 90 + _SC_THREAD_SAFE_FUNCTIONS :: 91 + _SC_THREAD_SPORADIC_SERVER :: 92 + _SC_THREAD_STACK_MIN :: 93 + _SC_THREAD_THREADS_MAX :: 94 + _SC_TIMEOUTS :: 95 + _SC_THREADS :: 96 + _SC_TRACE :: 97 + _SC_TRACE_EVENT_FILTER :: 98 + _SC_TRACE_INHERIT :: 99 + + _SC_TRACE_LOG :: 100 + _SC_TTY_NAME_MAX :: 101 + _SC_TYPED_MEMORY_OBJECTS :: 102 + _SC_V6_ILP32_OFF32 :: 103 + _SC_V6_ILP32_OFFBIG :: 104 + _SC_V6_LP64_OFF64 :: 105 + _SC_V6_LPBIG_OFFBIG :: 106 + _SC_ATEXIT_MAX :: 107 + _SC_XOPEN_CRYPT :: 108 + _SC_XOPEN_ENH_I18N :: 109 + + _SC_XOPEN_REALTIME :: 111 + _SC_XOPEN_REALTIME_THREADS :: 112 + _SC_XOPEN_SHM :: 113 + _SC_XOPEN_STREAMS :: 114 + _SC_XOPEN_UNIX :: 115 + _SC_XOPEN_VERSION :: 116 + _SC_IPV6 :: 118 + _SC_RAW_SOCKETS :: 119 + + _SC_SYMLOOP_MAX :: 120 + _SC_SS_REPL_MAX :: 126 + _SC_TRACE_EVENT_NAME_MAX :: 127 + _SC_TRACE_NAME_MAX :: 128 + _SC_TRACE_SYS_MAX :: 129 + _SC_TRACE_USER_EVENT_MAX :: 130 + + _POSIX_VDISABLE :: '\377' + +} else when ODIN_OS == .FreeBSD { + + _F_OK :: 0 + X_OK :: 0x01 + W_OK :: 0x02 + R_OK :: 0x04 + + F_LOCK :: 1 + F_TEST :: 3 + F_TLOCK :: 2 + F_ULOCK :: 0 + + _CS_PATH :: 1 + _CS_POSIX_V6_ILP32_OFF32_CFLAGS :: 2 + _CS_POSIX_V6_ILP32_OFF32_LDFLAGS :: 3 + _CS_POSIX_V6_ILP32_OFF32_LIBS :: 4 + _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS :: 5 + _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS :: 6 + _CS_POSIX_V6_ILP32_OFFBIG_LIBS :: 7 + _CS_POSIX_V6_LP64_OFF64_CFLAGS :: 8 + _CS_POSIX_V6_LP64_OFF64_LDFLAGS :: 9 + _CS_POSIX_V6_LP64_OFF64_LIBS :: 10 + _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS :: 11 + _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS :: 12 + _CS_POSIX_V6_LPBIG_OFFBIG_LIBS :: 13 + _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS :: 14 + + _PC_LINK_MAX :: 1 + _PC_MAX_CANON :: 2 + _PC_MAX_INPUT :: 3 + _PC_NAME_MAX :: 4 + _PC_PATH_MAX :: 5 + _PC_PIPE_BUF :: 6 + _PC_CHOWN_RESTRICTED :: 7 + _PC_NO_TRUNC :: 8 + _PC_VDISABLE :: 9 + _PC_2_SYMLINK :: 13 // NOTE: not in headers (freebsd) + _PC_ALLOC_SIZE_MIN :: 10 + _PC_ASYNC_IO :: 53 + _PC_FILESIZEBITS :: 12 + _PC_PRIO_IO :: 54 + _PC_REC_INCR_XFER_SIZE :: 14 + _PC_REC_MAX_XFER_SIZE :: 15 + _PC_REC_MIN_XFER_SIZE :: 16 + _PC_REC_XFER_ALIGN :: 17 + _PC_SYMLINK_MAX :: 18 + _PC_SYNC_IO :: 55 + + _SC_ARG_MAX :: 1 + _SC_CHILD_MAX :: 2 + _SC_CLK_TCK :: 3 + _SC_NGROUPS_MAX :: 4 + _SC_OPEN_MAX :: 5 + _SC_JOB_CONTROL :: 6 + _SC_SAVED_IDS :: 7 + _SC_VERSION :: 8 + _SC_BC_BASE_MAX :: 9 + + _SC_BC_DIM_MAX :: 10 + _SC_BC_SCALE_MAX :: 11 + _SC_BC_STRING_MAX :: 12 + _SC_COLL_WEIGHTS_MAX :: 13 + _SC_EXPR_NEST_MAX :: 14 + _SC_LINE_MAX :: 15 + _SC_RE_DUP_MAX :: 16 + _SC_2_VERSION :: 17 + _SC_2_C_BIND :: 18 + _SC_2_C_DEV :: 19 + + _SC_2_CHAR_TERM :: 20 + _SC_2_FORT_DEV :: 21 + _SC_2_FORT_RUN :: 22 + _SC_2_LOCALEDEF :: 23 + _SC_2_SW_DEV :: 24 + _SC_2_UPE :: 25 + _SC_STREAM_MAX :: 26 + _SC_TZNAME_MAX :: 27 + _SC_ASYNCHRONOUS_IO :: 28 + _SC_MAPPED_FILES :: 29 + + _SC_MEMLOCK :: 30 + _SC_MEMLOCK_RANGE :: 31 + _SC_MEMORY_PROTECTION :: 32 + _SC_MESSAGE_PASSING :: 33 + _SC_PRIORITIZED_IO :: 34 + _SC_PRIORITY_SCHEDULING :: 35 + _SC_REALTIME_SIGNALS :: 36 + _SC_SEMAPHORES :: 37 + _SC_FSYNC :: 38 + _SC_SHARED_MEMORY_OBJECTS :: 39 + + _SC_SYNCHRONIZED_IO :: 40 + _SC_TIMERS :: 41 + _SC_AIO_LISTIO_MAX :: 42 + _SC_AIO_MAX :: 43 + _SC_AIO_PRIO_DELTA_MAX :: 44 + _SC_DELAYTIMER_MAX :: 45 + _SC_MQ_OPEN_MAX :: 46 + _SC_PAGE_SIZE :: 47 + _SC_PAGESIZE :: _SC_PAGE_SIZE + _SC_RTSIG_MAX :: 48 + _SC_SEM_NSEMS_MAX :: 49 + + _SC_SEM_VALUE_MAX :: 50 + _SC_SIGQUEUE_MAX :: 51 + _SC_TIMER_MAX :: 52 + _SC_IOV_MAX :: 56 + _SC_2_PBS :: 59 + + _SC_2_PBS_ACCOUNTING :: 60 + _SC_2_PBS_CHECKPOINT :: 61 + _SC_2_PBS_LOCATE :: 62 + _SC_2_PBS_MESSAGE :: 63 + _SC_2_PBS_TRACK :: 64 + _SC_ADVISORY_INFO :: 65 + _SC_BARRIERS :: 66 + _SC_CLOCK_SELECTION :: 67 + _SC_CPUTIME :: 68 + + _SC_GETGR_R_SIZE_MAX :: 70 + _SC_GETPW_R_SIZE_MAX :: 71 + _SC_HOST_NAME_MAX :: 72 + _SC_LOGIN_NAME_MAX :: 73 + _SC_MONOTONIC_CLOCK :: 74 + _SC_MQ_PRIO_MAX :: 75 + _SC_READER_WRITER_LOCKS :: 76 + _SC_REGEXP :: 77 + _SC_SHELL :: 78 + _SC_SPAWN :: 79 + + _SC_SPIN_LOCKS :: 80 + _SC_SPORADIC_SERVER :: 81 + _SC_THREAD_ATTR_STACKADDR :: 82 + _SC_THREAD_ATTR_STACKSIZE :: 83 + _SC_THREAD_CPUTIME :: 84 + _SC_THREAD_DESTRUCTOR_ITERATIONS :: 85 + _SC_THREAD_KEYS_MAX :: 86 + _SC_THREAD_PRIO_INHERIT :: 87 + _SC_THREAD_PRIO_PROTECT :: 88 + _SC_THREAD_PRIORITY_SCHEDULING :: 89 + + _SC_THREAD_PROCESS_SHARED :: 90 + _SC_THREAD_SAFE_FUNCTIONS :: 91 + _SC_THREAD_SPORADIC_SERVER :: 92 + _SC_THREAD_STACK_MIN :: 93 + _SC_THREAD_THREADS_MAX :: 94 + _SC_TIMEOUTS :: 95 + _SC_THREADS :: 96 + _SC_TRACE :: 97 + _SC_TRACE_EVENT_FILTER :: 98 + _SC_TRACE_INHERIT :: 99 + + _SC_TRACE_LOG :: 100 + _SC_TTY_NAME_MAX :: 101 + _SC_TYPED_MEMORY_OBJECTS :: 102 + _SC_V6_ILP32_OFF32 :: 103 + _SC_V6_ILP32_OFFBIG :: 104 + _SC_V6_LP64_OFF64 :: 105 + _SC_V6_LPBIG_OFFBIG :: 106 + _SC_ATEXIT_MAX :: 107 + _SC_XOPEN_CRYPT :: 108 + _SC_XOPEN_ENH_I18N :: 109 + + _SC_XOPEN_REALTIME :: 111 + _SC_XOPEN_REALTIME_THREADS :: 112 + _SC_XOPEN_SHM :: 113 + _SC_XOPEN_STREAMS :: 114 + _SC_XOPEN_UNIX :: 115 + _SC_XOPEN_VERSION :: 116 + _SC_IPV6 :: 118 + _SC_RAW_SOCKETS :: 119 + + _SC_SYMLOOP_MAX :: 120 + _SC_SS_REPL_MAX :: 126 // NOTE: not in headers + _SC_TRACE_EVENT_NAME_MAX :: 127 // NOTE: not in headers + _SC_TRACE_NAME_MAX :: 128 // NOTE: not in headers + _SC_TRACE_SYS_MAX :: 129 // NOTE: not in headers + _SC_TRACE_USER_EVENT_MAX :: 130 // NOTE: not in headers + + _POSIX_VDISABLE :: 0xff + +} else when ODIN_OS == .NetBSD { + + _F_OK :: 0 + X_OK :: 0x01 + W_OK :: 0x02 + R_OK :: 0x04 + + F_LOCK :: 1 + F_TEST :: 3 + F_TLOCK :: 2 + F_ULOCK :: 0 + + _CS_PATH :: 1 + _CS_POSIX_V6_ILP32_OFF32_CFLAGS :: 2 + _CS_POSIX_V6_ILP32_OFF32_LDFLAGS :: 3 + _CS_POSIX_V6_ILP32_OFF32_LIBS :: 4 + _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS :: 5 + _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS :: 6 + _CS_POSIX_V6_ILP32_OFFBIG_LIBS :: 7 + _CS_POSIX_V6_LP64_OFF64_CFLAGS :: 8 + _CS_POSIX_V6_LP64_OFF64_LDFLAGS :: 9 + _CS_POSIX_V6_LP64_OFF64_LIBS :: 10 + _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS :: 11 + _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS :: 12 + _CS_POSIX_V6_LPBIG_OFFBIG_LIBS :: 13 + _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS :: 14 + + _PC_LINK_MAX :: 1 + _PC_MAX_CANON :: 2 + _PC_MAX_INPUT :: 3 + _PC_NAME_MAX :: 4 + _PC_PATH_MAX :: 5 + _PC_PIPE_BUF :: 6 + _PC_CHOWN_RESTRICTED :: 7 + _PC_NO_TRUNC :: 8 + _PC_VDISABLE :: 9 + _PC_2_SYMLINK :: 13 // NOTE: not in headers + _PC_ALLOC_SIZE_MIN :: 10 // NOTE: not in headers + _PC_ASYNC_IO :: 53 // NOTE: not in headers + _PC_FILESIZEBITS :: 11 + _PC_PRIO_IO :: 54 // NOTE: not in headers + _PC_REC_INCR_XFER_SIZE :: 14 // NOTE: not in headers + _PC_REC_MAX_XFER_SIZE :: 15 // NOTE: not in headers + _PC_REC_MIN_XFER_SIZE :: 16 // NOTE: not in headers + _PC_REC_XFER_ALIGN :: 17 // NOTE: not in headers + _PC_SYMLINK_MAX :: 12 + _PC_SYNC_IO :: 10 + + _SC_ARG_MAX :: 1 + _SC_CHILD_MAX :: 2 + _SC_NGROUPS_MAX :: 4 + _SC_OPEN_MAX :: 5 + _SC_JOB_CONTROL :: 6 + _SC_SAVED_IDS :: 7 + _SC_VERSION :: 8 + _SC_BC_BASE_MAX :: 9 + + _SC_BC_DIM_MAX :: 10 + _SC_BC_SCALE_MAX :: 11 + _SC_BC_STRING_MAX :: 12 + _SC_COLL_WEIGHTS_MAX :: 13 + _SC_EXPR_NEST_MAX :: 14 + _SC_LINE_MAX :: 15 + _SC_RE_DUP_MAX :: 16 + _SC_2_VERSION :: 17 + _SC_2_C_BIND :: 18 + _SC_2_C_DEV :: 19 + + _SC_2_CHAR_TERM :: 20 + _SC_2_FORT_DEV :: 21 + _SC_2_FORT_RUN :: 22 + _SC_2_LOCALEDEF :: 23 + _SC_2_SW_DEV :: 24 + _SC_2_UPE :: 25 + _SC_STREAM_MAX :: 26 + _SC_TZNAME_MAX :: 27 + _SC_PAGE_SIZE :: 28 + _SC_PAGESIZE :: _SC_PAGE_SIZE + _SC_FSYNC :: 29 + + _SC_XOPEN_SHM :: 30 + _SC_SYNCHRONIZED_IO :: 31 + _SC_IOV_MAX :: 32 + _SC_MAPPED_FILES :: 33 + _SC_MEMLOCK :: 34 + _SC_MEMLOCK_RANGE :: 35 + _SC_MEMORY_PROTECTION :: 36 + _SC_LOGIN_NAME_MAX :: 37 + _SC_MONOTONIC_CLOCK :: 38 + _SC_CLK_TCK :: 39 + + _SC_ATEXIT_MAX :: 40 + _SC_THREADS :: 41 + _SC_SEMAPHORES :: 42 + _SC_BARRIERS :: 43 + _SC_TIMERS :: 44 + _SC_SPIN_LOCKS :: 45 + _SC_READER_WRITER_LOCKS :: 46 + _SC_GETGR_R_SIZE_MAX :: 47 + _SC_GETPW_R_SIZE_MAX :: 48 + _SC_CLOCK_SELECTION :: 49 + + _SC_ASYNCHRONOUS_IO :: 50 + _SC_AIO_LISTIO_MAX :: 51 + _SC_AIO_MAX :: 52 + _SC_MESSAGE_PASSING :: 53 + _SC_MQ_OPEN_MAX :: 54 + _SC_MQ_PRIO_MAX :: 55 + _SC_PRIORITY_SCHEDULING :: 56 + _SC_THREAD_DESTRUCTOR_ITERATIONS :: 57 + _SC_THREAD_KEYS_MAX :: 58 + _SC_THREAD_STACK_MIN :: 59 + + _SC_THREAD_THREADS_MAX :: 60 + _SC_THREAD_ATTR_STACKADDR :: 61 + _SC_THREAD_ATTR_STACKSIZE :: 62 + _SC_THREAD_PRIORITY_SCHEDULING :: 63 + _SC_THREAD_PRIO_INHERIT :: 64 + _SC_THREAD_PRIO_PROTECT :: 65 + _SC_THREAD_PROCESS_SHARED :: 66 + _SC_THREAD_SAFE_FUNCTIONS :: 67 + _SC_TTY_NAME_MAX :: 68 + _SC_HOST_NAME_MAX :: 69 + + _SC_PASS_MAX :: 70 + _SC_REGEXP :: 71 + _SC_SHELL :: 72 + _SC_SYMLOOP_MAX :: 73 + _SC_V6_ILP32_OFF32 :: 74 + _SC_V6_ILP32_OFFBIG :: 75 + _SC_V6_LP64_OFF64 :: 76 + _SC_V6_LPBIG_OFFBIG :: 77 + + _SC_2_PBS :: 80 + _SC_2_PBS_ACCOUNTING :: 81 + _SC_2_PBS_CHECKPOINT :: 82 + _SC_2_PBS_LOCATE :: 83 + _SC_2_PBS_MESSAGE :: 84 + _SC_2_PBS_TRACK :: 85 + _SC_SPAWN :: 86 + _SC_SHARED_MEMORY_OBJECTS :: 87 + _SC_TIMER_MAX :: 88 + _SC_SEM_NSEMS_MAX :: 89 + + _SC_CPUTIME :: 90 + _SC_THREAD_CPUTIME :: 91 + _SC_DELAYTIMER_MAX :: 92 + _SC_SIGQUEUE_MAX :: 93 + _SC_REALTIME_SIGNALS :: 94 + _SC_RTSIG_MAX :: 95 + + _POSIX_VDISABLE :: '\377' + + // NOTE: following are not defined in netbsd headers. + + _SC_SPORADIC_SERVER :: 81 + _SC_SEM_VALUE_MAX :: 50 + + _SC_TRACE :: 97 + _SC_TRACE_EVENT_FILTER :: 98 + _SC_TRACE_INHERIT :: 99 + _SC_TRACE_LOG :: 100 + _SC_TYPED_MEMORY_OBJECTS :: 102 + + _SC_THREAD_SPORADIC_SERVER :: 92 + _SC_TIMEOUTS :: 95 + + _SC_XOPEN_CRYPT :: 108 + _SC_XOPEN_ENH_I18N :: 109 + _SC_XOPEN_REALTIME :: 111 + _SC_XOPEN_REALTIME_THREADS :: 112 + _SC_XOPEN_STREAMS :: 114 + _SC_XOPEN_UNIX :: 115 + _SC_XOPEN_VERSION :: 116 + _SC_IPV6 :: 118 + _SC_RAW_SOCKETS :: 119 + + _SC_PRIORITIZED_IO :: 34 + _SC_AIO_PRIO_DELTA_MAX :: 44 + _SC_ADVISORY_INFO :: 65 + _SC_SS_REPL_MAX :: 126 + _SC_TRACE_EVENT_NAME_MAX :: 127 + _SC_TRACE_NAME_MAX :: 128 + _SC_TRACE_SYS_MAX :: 129 + _SC_TRACE_USER_EVENT_MAX :: 130 + +} else when ODIN_OS == .OpenBSD { + + _F_OK :: 0 + X_OK :: 0x01 + W_OK :: 0x02 + R_OK :: 0x04 + + F_LOCK :: 1 + F_TEST :: 3 + F_TLOCK :: 2 + F_ULOCK :: 0 + + _CS_PATH :: 1 + _CS_POSIX_V6_ILP32_OFF32_CFLAGS :: 2 + _CS_POSIX_V6_ILP32_OFF32_LDFLAGS :: 3 + _CS_POSIX_V6_ILP32_OFF32_LIBS :: 4 + _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS :: 5 + _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS :: 6 + _CS_POSIX_V6_ILP32_OFFBIG_LIBS :: 7 + _CS_POSIX_V6_LP64_OFF64_CFLAGS :: 8 + _CS_POSIX_V6_LP64_OFF64_LDFLAGS :: 9 + _CS_POSIX_V6_LP64_OFF64_LIBS :: 10 + _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS :: 11 + _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS :: 12 + _CS_POSIX_V6_LPBIG_OFFBIG_LIBS :: 13 + _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS :: 14 + + _PC_LINK_MAX :: 1 + _PC_MAX_CANON :: 2 + _PC_MAX_INPUT :: 3 + _PC_NAME_MAX :: 4 + _PC_PATH_MAX :: 5 + _PC_PIPE_BUF :: 6 + _PC_CHOWN_RESTRICTED :: 7 + _PC_NO_TRUNC :: 8 + _PC_VDISABLE :: 9 + _PC_2_SYMLINK :: 10 + _PC_ALLOC_SIZE_MIN :: 11 + _PC_ASYNC_IO :: 12 + _PC_FILESIZEBITS :: 13 + _PC_PRIO_IO :: 14 + _PC_REC_INCR_XFER_SIZE :: 15 + _PC_REC_MAX_XFER_SIZE :: 16 + _PC_REC_MIN_XFER_SIZE :: 17 + _PC_REC_XFER_ALIGN :: 18 + _PC_SYMLINK_MAX :: 19 + _PC_SYNC_IO :: 20 + + _SC_ARG_MAX :: 1 + _SC_CHILD_MAX :: 2 + _SC_CLK_TCK :: 3 + _SC_NGROUPS_MAX :: 4 + _SC_OPEN_MAX :: 5 + _SC_JOB_CONTROL :: 6 + _SC_SAVED_IDS :: 7 + _SC_VERSION :: 8 + _SC_BC_BASE_MAX :: 9 + + _SC_BC_DIM_MAX :: 10 + _SC_BC_SCALE_MAX :: 11 + _SC_BC_STRING_MAX :: 12 + _SC_COLL_WEIGHTS_MAX :: 13 + _SC_EXPR_NEST_MAX :: 14 + _SC_LINE_MAX :: 15 + _SC_RE_DUP_MAX :: 16 + _SC_2_VERSION :: 17 + _SC_2_C_BIND :: 18 + _SC_2_C_DEV :: 19 + + _SC_2_CHAR_TERM :: 20 + _SC_2_FORT_DEV :: 21 + _SC_2_FORT_RUN :: 22 + _SC_2_LOCALEDEF :: 23 + _SC_2_SW_DEV :: 24 + _SC_2_UPE :: 25 + _SC_STREAM_MAX :: 26 + _SC_TZNAME_MAX :: 27 + _SC_PAGESIZE :: 28 + _SC_PAGE_SIZE :: _SC_PAGESIZE + _SC_FSYNC :: 29 + + _SC_XOPEN_SHM :: 30 + _SC_SEM_NSEMS_MAX :: 31 + _SC_SEM_VALUE_MAX :: 32 + _SC_HOST_NAME_MAX :: 33 + _SC_MONOTONIC_CLOCK :: 34 + _SC_2_PBS :: 35 + _SC_2_PBS_ACCOUNTING :: 36 + _SC_2_PBS_CHECKPOINT :: 37 + _SC_2_PBS_LOCATE :: 38 + _SC_2_PBS_MESSAGE :: 39 + + _SC_2_PBS_TRACK :: 40 + _SC_ADVISORY_INFO :: 41 + _SC_AIO_LISTIO_MAX :: 42 + _SC_AIO_MAX :: 43 + _SC_AIO_PRIO_DELTA_MAX :: 44 + _SC_ASYNCHRONOUS_IO :: 45 + _SC_ATEXIT_MAX :: 46 + _SC_BARRIERS :: 47 + _SC_CLOCK_SELECTION :: 48 + _SC_CPUTIME :: 49 + + _SC_DELAYTIMER_MAX :: 50 + _SC_IOV_MAX :: 51 + _SC_IPV6 :: 52 + _SC_MAPPED_FILES :: 53 + _SC_MEMLOCK :: 54 + _SC_MEMLOCK_RANGE :: 55 + _SC_MEMORY_PROTECTION :: 56 + _SC_MESSAGE_PASSING :: 57 + _SC_MQ_OPEN_MAX :: 58 + _SC_MQ_PRIO_MAX :: 59 + + _SC_PRIORITIZED_IO :: 60 + _SC_PRIORITY_SCHEDULING :: 61 + _SC_RAW_SOCKETS :: 62 + _SC_READER_WRITER_LOCKS :: 63 + _SC_REALTIME_SIGNALS :: 64 + _SC_REGEXP :: 65 + _SC_RTSIG_MAX :: 66 + _SC_SEMAPHORES :: 67 + _SC_SHARED_MEMORY_OBJECTS :: 68 + _SC_SHELL :: 69 + + _SC_SIGQUEUE_MAX :: 70 + _SC_SPAWN :: 71 + _SC_SPIN_LOCKS :: 72 + _SC_SPORADIC_SERVER :: 73 + _SC_SS_REPL_MAX :: 74 + _SC_SYNCHRONIZED_IO :: 75 + _SC_SYMLOOP_MAX :: 76 + _SC_THREAD_ATTR_STACKADDR :: 77 + _SC_THREAD_ATTR_STACKSIZE :: 78 + _SC_THREAD_CPUTIME :: 79 + + _SC_THREAD_DESTRUCTOR_ITERATIONS :: 80 + _SC_THREAD_KEYS_MAX :: 81 + _SC_THREAD_PRIO_INHERIT :: 82 + _SC_THREAD_PRIO_PROTECT :: 83 + _SC_THREAD_PRIORITY_SCHEDULING :: 84 + _SC_THREAD_PROCESS_SHARED :: 85 + _SC_THREAD_ROBUST_PRIO_INHERIT :: 86 + _SC_THREAD_ROBUST_PRIO_PROTECT :: 87 + _SC_THREAD_SPORADIC_SERVER :: 88 + _SC_THREAD_STACK_MIN :: 89 + + _SC_THREAD_THREADS_MAX :: 90 + _SC_THREADS :: 91 + _SC_TIMEOUTS :: 92 + _SC_TIMER_MAX :: 93 + _SC_TIMERS :: 94 + _SC_TRACE :: 95 + _SC_TRACE_EVENT_FILTER :: 96 + _SC_TRACE_EVENT_NAME_MAX :: 97 + _SC_TRACE_INHERIT :: 98 + _SC_TRACE_LOG :: 99 + + _SC_GETGR_R_SIZE_MAX :: 100 + _SC_GETPW_R_SIZE_MAX :: 101 + _SC_LOGIN_NAME_MAX :: 102 + _SC_THREAD_SAFE_FUNCTIONS :: 103 + _SC_TRACE_NAME_MAX :: 104 + _SC_TRACE_SYS_MAX :: 105 + _SC_TRACE_USER_EVENT_MAX :: 106 + _SC_TTY_NAME_MAX :: 107 + _SC_TYPED_MEMORY_OBJECTS :: 108 + _SC_V6_ILP32_OFF32 :: 109 + + _SC_V6_ILP32_OFFBIG :: 110 + _SC_V6_LP64_OFF64 :: 111 + _SC_V6_LPBIG_OFFBIG :: 112 + _SC_V7_ILP32_OFF32 :: 113 + _SC_V7_ILP32_OFFBIG :: 114 + _SC_V7_LP64_OFF64 :: 115 + _SC_V7_LPBIG_OFFBIG :: 116 + _SC_XOPEN_CRYPT :: 117 + _SC_XOPEN_ENH_I18N :: 118 + _SC_XOPEN_LEGACY :: 119 + + _SC_XOPEN_REALTIME :: 120 + _SC_XOPEN_REALTIME_THREADS :: 121 + _SC_XOPEN_STREAMS :: 122 + _SC_XOPEN_UNIX :: 123 + _SC_XOPEN_UUCP :: 124 + _SC_XOPEN_VERSION :: 125 + + _SC_PHYS_PAGES :: 500 + _SC_AVPHYS_PAGES :: 501 + _SC_NPROCESSORS_CONF :: 502 + _SC_NPROCESSORS_ONLN :: 503 + + _POSIX_VDISABLE :: '\377' + +} else { + #panic("posix is unimplemented for the current target") +} + diff --git a/core/sys/posix/utime.odin b/core/sys/posix/utime.odin new file mode 100644 index 000000000..591a6db06 --- /dev/null +++ b/core/sys/posix/utime.odin @@ -0,0 +1,36 @@ +package posix + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// utime.h - access and modification time structure + +foreign lib { + /* + Set file access and modification times. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/utime.html ]] + */ + @(link_name=LUTIME) + utime :: proc(path: cstring, times: ^utimbuf) -> result --- +} + +when ODIN_OS == .NetBSD { + @(private) LUTIME :: "__utime50" +} else { + @(private) LUTIME :: "utime" +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + utimbuf :: struct { + actime: time_t, /* [PSX] access time (seconds since epoch) */ + modtime: time_t, /* [PSX] modification time (seconds since epoch) */ + } + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/posix/wordexp.odin b/core/sys/posix/wordexp.odin new file mode 100644 index 000000000..d730db0f7 --- /dev/null +++ b/core/sys/posix/wordexp.odin @@ -0,0 +1,107 @@ +package posix + +import "core:c" + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// wordexp.h - word-expansion type + +foreign lib { + /* + Perform word expansion. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/wordexp.html ]] + */ + wordexp :: proc(words: cstring, pwordexp: ^wordexp_t, flags: WRDE_Flags) -> WRDE_Errno --- + + /* + Free the space allocated during word expansion. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/wordexp.html ]] + */ + wordfree :: proc(pwordexp: ^wordexp_t) --- +} + +WRDE_Flag_Bits :: enum c.int { + // Appends words to those previously generated. + APPEND = log2(WRDE_APPEND), + // Number of null pointers to prepend to we_wordv. + DOOFFS = log2(WRDE_DOOFFS), + // Fail if command substitution is requested. + NOCMD = log2(WRDE_NOCMD), + // The pwordexp argument was passed to a previous successful call to wordexp(), + // and has not been passed to wordfree(). + REUSE = log2(WRDE_REUSE), + // Do not redirect stderr to /dev/null. + SHOWERR = log2(WRDE_SHOWERR), + // Report error on attempt to expand an undefined shell variable. + UNDEF = log2(WRDE_UNDEF), +} +WRDE_Flags :: bit_set[WRDE_Flag_Bits; c.int] + +WRDE_Errno :: enum c.int { + OK = 0, + // One of the unquoted characters- , '|', '&', ';', '<', '>', '(', ')', '{', '}' - + // appears in words in an inappropriate context. + BADCHAR = WRDE_BADCHAR, + // Reference to undefined shell variable when WRDE_UNDEF is set in flags. + BADVAL = WRDE_BADVAL, + // Command substitution requested when WRDE_NOCMD was set in flags. + CMDSUB = WRDE_CMDSUB, + // Attempt to allocate memory failed. + NOSPACE = WRDE_NOSPACE, + // Shell syntax error, such as unbalanced parentheses or an unterminated string. + SYNTAX = WRDE_SYNTAX, +} + +when ODIN_OS == .Darwin { + + wordexp_t :: struct { + we_wordc: c.size_t, /* [PSX] count of words matched by words */ + we_wordv: [^]cstring, /* [PSX] pointer to list of expanded words */ + we_offs: c.size_t, /* [PSX] slots to reserve at the beginning of we_wordv */ + } + + WRDE_APPEND :: 0x01 + WRDE_DOOFFS :: 0x02 + WRDE_NOCMD :: 0x04 + WRDE_REUSE :: 0x08 + WRDE_SHOWERR :: 0x10 + WRDE_UNDEF :: 0x20 + + WRDE_BADCHAR :: 1 + WRDE_BADVAL :: 2 + WRDE_CMDSUB :: 3 + WRDE_NOSPACE :: 4 + WRDE_SYNTAX :: 6 + +} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { + + wordexp_t :: struct { + we_wordc: c.size_t, /* [PSX] count of words matched by words */ + we_wordv: [^]cstring, /* [PSX] pointer to list of expanded words */ + we_offs: c.size_t, /* [PSX] slots to reserve at the beginning of we_wordv */ + we_strings: [^]byte, /* storage for wordv strings */ + we_nbytes: c.size_t, /* size of we_strings */ + } + + WRDE_APPEND :: 0x01 + WRDE_DOOFFS :: 0x02 + WRDE_NOCMD :: 0x04 + WRDE_REUSE :: 0x08 + WRDE_SHOWERR :: 0x10 + WRDE_UNDEF :: 0x20 + + WRDE_BADCHAR :: 1 + WRDE_BADVAL :: 2 + WRDE_CMDSUB :: 3 + WRDE_NOSPACE :: 4 + WRDE_SYNTAX :: 6 + +} else { + #panic("posix is unimplemented for the current target") +} diff --git a/core/sys/unix/pthread_netbsd.odin b/core/sys/unix/pthread_netbsd.odin index afbbc321c..9107f1139 100644 --- a/core/sys/unix/pthread_netbsd.odin +++ b/core/sys/unix/pthread_netbsd.odin @@ -2,7 +2,7 @@ package unix import "core:c" -pthread_t :: distinct u64 +pthread_t :: distinct rawptr SEM_T_SIZE :: 8 diff --git a/core/sys/unix/pthread_unix.odin b/core/sys/unix/pthread_unix.odin index c876a214a..68a0859b4 100644 --- a/core/sys/unix/pthread_unix.odin +++ b/core/sys/unix/pthread_unix.odin @@ -5,6 +5,11 @@ foreign import "system:pthread" import "core:c" +timespec :: struct { + tv_sec: i64, + tv_nsec: i64, +} + // // On success, these functions return 0. // diff --git a/core/sys/unix/time_unix.odin b/core/sys/unix/time_unix.odin deleted file mode 100644 index 442202d36..000000000 --- a/core/sys/unix/time_unix.odin +++ /dev/null @@ -1,83 +0,0 @@ -//+build linux, darwin, freebsd, openbsd, netbsd, haiku -package unix - -when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" -} else { - foreign import libc "system:c" -} - -import "core:c" - -when ODIN_OS == .NetBSD { - @(default_calling_convention="c") - foreign libc { - @(link_name="__clock_gettime50") clock_gettime :: proc(clock_id: u64, timespec: ^timespec) -> c.int --- - @(link_name="__nanosleep50") nanosleep :: proc(requested, remaining: ^timespec) -> c.int --- - @(link_name="sleep") sleep :: proc(seconds: c.uint) -> c.int --- - } -} else { - @(default_calling_convention="c") - foreign libc { - clock_gettime :: proc(clock_id: u64, timespec: ^timespec) -> c.int --- - sleep :: proc(seconds: c.uint) -> c.int --- - nanosleep :: proc(requested, remaining: ^timespec) -> c.int --- - } -} - -timespec :: struct { - tv_sec: i64, // seconds - tv_nsec: i64, // nanoseconds -} - -when ODIN_OS == .OpenBSD { - CLOCK_REALTIME :: 0 - CLOCK_PROCESS_CPUTIME_ID :: 2 - CLOCK_MONOTONIC :: 3 - CLOCK_THREAD_CPUTIME_ID :: 4 - CLOCK_UPTIME :: 5 - CLOCK_BOOTTIME :: 6 - - // CLOCK_MONOTONIC_RAW doesn't exist, use CLOCK_MONOTONIC - CLOCK_MONOTONIC_RAW :: CLOCK_MONOTONIC -} else { - CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time. - CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep. - CLOCK_PROCESS_CPUTIME_ID :: 2 - CLOCK_THREAD_CPUTIME_ID :: 3 - CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP. - CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained." - CLOCK_MONOTONIC_COARSE :: 6 - CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep. - CLOCK_REALTIME_ALARM :: 8 - CLOCK_BOOTTIME_ALARM :: 9 -} - -// TODO(tetra, 2019-11-05): The original implementation of this package for Darwin used this constants. -// I do not know if Darwin programmers are used to the existance of these constants or not, so -// I'm leaving aliases to them for now. -CLOCK_SYSTEM :: CLOCK_REALTIME -CLOCK_CALENDAR :: CLOCK_MONOTONIC - -boot_time_in_nanoseconds :: proc "c" () -> i64 { - ts_now, ts_boottime: timespec - clock_gettime(CLOCK_REALTIME, &ts_now) - clock_gettime(CLOCK_BOOTTIME, &ts_boottime) - - ns := (ts_now.tv_sec - ts_boottime.tv_sec) * 1e9 + ts_now.tv_nsec - ts_boottime.tv_nsec - return i64(ns) -} - -seconds_since_boot :: proc "c" () -> f64 { - ts_boottime: timespec - clock_gettime(CLOCK_BOOTTIME, &ts_boottime) - return f64(ts_boottime.tv_sec) + f64(ts_boottime.tv_nsec) / 1e9 -} - -inline_nanosleep :: proc "c" (nanoseconds: i64) -> (remaining: timespec, res: i32) { - s, ns := nanoseconds / 1e9, nanoseconds % 1e9 - requested := timespec{tv_sec=s, tv_nsec=ns} - res = nanosleep(&requested, &remaining) - return -} - diff --git a/core/time/time_linux.odin b/core/time/time_linux.odin new file mode 100644 index 000000000..649f601dc --- /dev/null +++ b/core/time/time_linux.odin @@ -0,0 +1,38 @@ +package time + +import "core:sys/linux" + +_IS_SUPPORTED :: true + +_now :: proc "contextless" () -> Time { + time_spec_now, _ := linux.clock_gettime(.REALTIME) + ns := time_spec_now.time_sec * 1e9 + time_spec_now.time_nsec + return Time{_nsec=i64(ns)} +} + +_sleep :: proc "contextless" (d: Duration) { + ds := duration_seconds(d) + seconds := uint(ds) + nanoseconds := uint((ds - f64(seconds)) * 1e9) + + ts := linux.Time_Spec{ + time_sec = seconds, + time_nsec = nanoseconds, + } + + for { + if linux.nanosleep(&ts, &ts) != .EINTR { + break + } + } +} + +_tick_now :: proc "contextless" () -> Tick { + t, _ := linux.clock_gettime(.MONOTONIC_RAW) + return Tick{_nsec = i64(t.time_sec*1e9 + t.time_nsec)} +} + +_yield :: proc "contextless" () { + linux.sched_yield() +} + diff --git a/core/time/time_unix.odin b/core/time/time_unix.odin index f3e0d6640..61543b99c 100644 --- a/core/time/time_unix.odin +++ b/core/time/time_unix.odin @@ -1,34 +1,50 @@ //+private -//+build linux, darwin, freebsd, openbsd, netbsd, haiku +//+build darwin, freebsd, openbsd, netbsd, haiku package time -import "core:sys/unix" +import "core:sys/posix" -_IS_SUPPORTED :: true // NOTE: Times on Darwin are UTC. +_IS_SUPPORTED :: true _now :: proc "contextless" () -> Time { - time_spec_now: unix.timespec - unix.clock_gettime(unix.CLOCK_REALTIME, &time_spec_now) - ns := time_spec_now.tv_sec * 1e9 + time_spec_now.tv_nsec + time_spec_now: posix.timespec + posix.clock_gettime(.REALTIME, &time_spec_now) + ns := i64(time_spec_now.tv_sec) * 1e9 + time_spec_now.tv_nsec return Time{_nsec=ns} } _sleep :: proc "contextless" (d: Duration) { ds := duration_seconds(d) - seconds := u32(ds) + seconds := posix.time_t(ds) nanoseconds := i64((ds - f64(seconds)) * 1e9) - if seconds > 0 { unix.sleep(seconds) } - if nanoseconds > 0 { unix.inline_nanosleep(nanoseconds) } + ts := posix.timespec{ + tv_sec = seconds, + tv_nsec = nanoseconds, + } + + for { + res := posix.nanosleep(&ts, &ts) + if res == .OK || posix.errno() != .EINTR { + break + } + } +} + +when ODIN_OS == .Darwin { + TICK_CLOCK :: posix.Clock(4) // CLOCK_MONOTONIC_RAW +} else { + // It looks like the BSDs don't have a CLOCK_MONOTONIC_RAW equivalent. + TICK_CLOCK :: posix.Clock.MONOTONIC } _tick_now :: proc "contextless" () -> Tick { - t: unix.timespec - unix.clock_gettime(unix.CLOCK_MONOTONIC_RAW, &t) - return Tick{_nsec = t.tv_sec*1e9 + t.tv_nsec} + t: posix.timespec + posix.clock_gettime(TICK_CLOCK, &t) + return Tick{_nsec = i64(t.tv_sec)*1e9 + t.tv_nsec} } _yield :: proc "contextless" () { - unix.sched_yield() + posix.sched_yield() } diff --git a/examples/all/all_posix.odin b/examples/all/all_posix.odin new file mode 100644 index 000000000..819dd6dd3 --- /dev/null +++ b/examples/all/all_posix.odin @@ -0,0 +1,6 @@ +//+build darwin, openbsd, freebsd, netbsd +package all + +import posix "core:sys/posix" + +_ :: posix diff --git a/src/big_int.cpp b/src/big_int.cpp index e350687b4..83235483c 100644 --- a/src/big_int.cpp +++ b/src/big_int.cpp @@ -621,3 +621,7 @@ gb_internal String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 } return make_string(cast(u8 *)buf.data, buf.count); } + +gb_internal int big_int_log2(BigInt const *x) { + return mp_count_bits(x) - 1; +} diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index bde102a8d..e5282f63e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3979,6 +3979,23 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } + case BuiltinProc_constant_log2: { + Operand o = {}; + check_expr(c, &o, ce->args[0]); + + if (!is_type_integer(o.type) && (o.mode != Addressing_Constant)) { + error(ce->args[0], "Expected a constant integer for '%.*s'", LIT(builtin_name)); + return false; + } + + int log2 = big_int_log2(&o.value.value_integer); + + operand->mode = Addressing_Constant; + operand->value = exact_value_i64(cast(i64)log2); + operand->type = t_untyped_integer; + break; + } + case BuiltinProc_soa_struct: { Operand x = {}; Operand y = {}; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 1425aafa8..0d4b47037 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -756,13 +756,29 @@ gb_internal bool are_signatures_similar_enough(Type *a_, Type *b_) { for (isize i = 0; i < a->param_count; i++) { Type *x = core_type(a->params->Tuple.variables[i]->type); Type *y = core_type(b->params->Tuple.variables[i]->type); + + if (x->kind == Type_BitSet && x->BitSet.underlying) { + x = core_type(x->BitSet.underlying); + } + if (y->kind == Type_BitSet && y->BitSet.underlying) { + y = core_type(y->BitSet.underlying); + } + if (!signature_parameter_similar_enough(x, y)) { return false; } } for (isize i = 0; i < a->result_count; i++) { - Type *x = base_type(a->results->Tuple.variables[i]->type); - Type *y = base_type(b->results->Tuple.variables[i]->type); + Type *x = core_type(a->results->Tuple.variables[i]->type); + Type *y = core_type(b->results->Tuple.variables[i]->type); + + if (x->kind == Type_BitSet && x->BitSet.underlying) { + x = core_type(x->BitSet.underlying); + } + if (y->kind == Type_BitSet && y->BitSet.underlying) { + y = core_type(y->BitSet.underlying); + } + if (!signature_parameter_similar_enough(x, y)) { return false; } diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 6245dadaf..ef07938c7 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -46,6 +46,8 @@ enum BuiltinProcId { BuiltinProc_has_target_feature, + BuiltinProc_constant_log2, + BuiltinProc_transpose, BuiltinProc_outer_product, BuiltinProc_hadamard_product, @@ -380,6 +382,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("has_target_feature"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("constant_log2"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("transpose"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("outer_product"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("hadamard_product"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/tests/core/normal.odin b/tests/core/normal.odin index e35d86598..45c66ed8d 100644 --- a/tests/core/normal.odin +++ b/tests/core/normal.odin @@ -38,6 +38,7 @@ download_assets :: proc() { @(require) import "slice" @(require) import "strconv" @(require) import "strings" +@(require) import "sys/posix" @(require) import "sys/windows" @(require) import "text/i18n" @(require) import "text/match" diff --git a/tests/core/sys/posix/posix.odin b/tests/core/sys/posix/posix.odin new file mode 100644 index 000000000..1942bfbda --- /dev/null +++ b/tests/core/sys/posix/posix.odin @@ -0,0 +1,211 @@ +//+build darwin, freebsd, openbsd, netbsd +package tests_core_posix + +import "core:sys/posix" +import "core:testing" +import "core:log" +import "core:strings" +import "core:path/filepath" + +@(test) +test_arpa_inet :: proc(t: ^testing.T) { + + check :: proc(t: ^testing.T, $af: posix.AF, src: cstring, expect: posix.pton_result, loc := #caller_location) { + when af == .INET { + addr: posix.in_addr + dst: [posix.INET_ADDRSTRLEN]byte + } else { + addr: posix.in6_addr + dst: [posix.INET6_ADDRSTRLEN]byte + } + + res := posix.inet_pton(af, src, &addr, size_of(addr)) + testing.expect_value(t, res, expect, loc) + + if expect == .SUCCESS { + back := posix.inet_ntop(af, &addr, raw_data(dst[:]), len(dst)) + testing.expect_value(t, back, src, loc) + + when af == .INET { + back = posix.inet_ntoa(addr) + testing.expect_value(t, back, src, loc) + } + } + } + + check(t, .INET, "127.0.0.1", .SUCCESS) + check(t, .INET, "blah", .INVALID) + check(t, .INET6, "::1", .SUCCESS) + check(t, .INET6, "L", .INVALID) + check(t, .UNIX, "127.0.0.1", .AFNOSUPPORT) +} + +@(test) +test_dirent :: proc(t: ^testing.T) { + test := #load_directory(#directory) + test_map: map[string]struct{} + defer delete(test_map) + + test_map[".."] = {} + test_map["."] = {} + + for file in test { + test_map[filepath.base(file.name)] = {} + } + + { + list: [^]^posix.dirent + ret := posix.scandir(#directory, &list) + testing.expectf(t, ret >= 0, "%v >= 0: %v", ret, posix.strerror(posix.errno())) + defer posix.free(list) + + entries := list[:ret] + for entry in entries { + defer posix.free(entry) + + if entry.d_type != .REG { + continue + } + + name := string(cstring(raw_data(entry.d_name[:]))) + testing.expectf(t, name in test_map, "%v in %v", name, test_map) + } + } + + { + dir := posix.opendir(#directory) + defer posix.closedir(dir) + + for { + posix.set_errno(.NONE) + entry := posix.readdir(dir) + if entry == nil { + testing.expect_value(t, posix.errno(), posix.Errno.NONE) + break + } + + if entry.d_type != .REG { + continue + } + + name := string(cstring(raw_data(entry.d_name[:]))) + testing.expectf(t, name in test_map, "%v in %v", name, test_map) + } + } +} + +@(test) +test_errno :: proc(t: ^testing.T) { + posix.errno(posix.Errno.ENOMEM) + testing.expect_value(t, posix.errno(), posix.Errno.ENOMEM) + + res := posix.open("", {}) + testing.expect_value(t, res, -1) + testing.expect_value(t, posix.errno(), posix.Errno.ENOENT) +} + +@(test) +test_fcntl :: proc(t: ^testing.T) { + res := posix.open(#file, { .WRONLY, .CREAT, .EXCL }) + testing.expect_value(t, res, -1) + testing.expect_value(t, posix.errno(), posix.Errno.EEXIST) +} + +@(test) +test_fnmatch :: proc(t: ^testing.T) { + testing.expect_value(t, posix.fnmatch("*.odin", #file, {}), 0) + testing.expect_value(t, posix.fnmatch("*.txt", #file, {}), posix.FNM_NOMATCH) + testing.expect_value(t, posix.fnmatch("**/*.odin", #file, {}), 0) +} + +@(test) +test_glob :: proc(t: ^testing.T) { + glob: posix.glob_t + res := posix.glob(#directory + ":)))))))", {}, nil, &glob) + testing.expect_value(t, res, posix.Glob_Result.NOMATCH) + posix.globfree(&glob) +} + +@(test) +test_langinfo :: proc(t: ^testing.T) { + locale := posix.setlocale(.TIME, nil) + testing.expectf(t, locale == "POSIX" || locale == "C", "invalid locale for test: %v", locale) + + day1 := posix.nl_langinfo(.DAY_1) + testing.expect_value(t, day1, "Sunday") +} + +@(test) +test_libgen :: proc(t: ^testing.T) { + tests := [][3]cstring{ + { "usr", ".", "usr" }, + { "usr/", ".", "usr" }, + { "", ".", "." }, + { "/", "/", "/" }, + { "//", "/", "/" }, + { "///", "/", "/" }, + { "/usr/", "/", "usr" }, + { "/usr/lib", "/usr", "lib" }, + { "//usr//lib//", "//usr", "lib" }, + { "/home//dwc//test", "/home//dwc", "test" }, + } + + for test in tests { + // NOTE: dir/basename can change their input so they can't be literals. + + dinput := strings.clone_to_cstring(string(test[0])) + defer delete(dinput) + + dir := posix.dirname(dinput) + testing.expectf(t, dir == test[1], "dirname(%q) == %q, expected %q", test[0], dir, test[1]) + + binput := strings.clone_to_cstring(string(test[0])) + defer delete(binput) + + base := posix.basename(binput) + testing.expectf(t, base == test[2], "basename(%q) == %q, expected %q", test[0], base, test[2]) + } +} + +@(test) +test_locale :: proc(t: ^testing.T) { + lconv := posix.localeconv() + testing.expect(t, lconv != nil) + + locale := posix.setlocale(.ALL, nil) + testing.expectf(t, locale == "POSIX" || locale == "C", "%q is not POSIX or C", locale) +} + +@(test) +test_monetary :: proc(t: ^testing.T) { + when ODIN_OS == .Darwin && .Address in ODIN_SANITIZER_FLAGS { + log.warn("skipping on darwin with -sanitize:address, this fails inside macOS (also from C/clang)") + return + } + + value := 123456.789 + buf: [128]byte + size := posix.strfmon(raw_data(buf[:]), len(buf), "%n", value) + testing.expectf(t, int(size) != -1, "strfmon failure: %v", posix.strerror(posix.errno())) + log.debug(string(buf[:size])) +} + +@(test) +test_stat :: proc(t: ^testing.T) { + testing.expect_value(t, posix.S_IRWXU, transmute(posix.mode_t)posix._mode_t(posix._S_IRWXU)) + testing.expect_value(t, posix.S_IRWXG, transmute(posix.mode_t)posix._mode_t(posix._S_IRWXG)) + testing.expect_value(t, posix.S_IRWXO, transmute(posix.mode_t)posix._mode_t(posix._S_IRWXO)) + testing.expect_value(t, posix._S_IFMT, transmute(posix.mode_t)posix._mode_t(posix.__S_IFMT)) +} + +@(test) +test_termios :: proc(t: ^testing.T) { + testing.expect_value(t, transmute(posix.CControl_Flags)posix.tcflag_t(posix._CSIZE), posix.CSIZE) + + testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._NLDLY), posix.NLDLY) + testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._CRDLY), posix.CRDLY) + testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._TABDLY), posix.TABDLY) + testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._BSDLY), posix.BSDLY) + testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._VTDLY), posix.VTDLY) + testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._FFDLY), posix.FFDLY) +} diff --git a/tests/core/sys/posix/structs.odin b/tests/core/sys/posix/structs.odin new file mode 100644 index 000000000..bdb1c24e3 --- /dev/null +++ b/tests/core/sys/posix/structs.odin @@ -0,0 +1,127 @@ +//+build darwin, freebsd, openbsd, netbsd +package tests_core_posix + +import "core:log" +import "core:testing" +import "core:sys/posix" + +// This test tests some of the process APIs of posix while also double checking size and alignment +// of the structs we bound. + +@(test) +execute_struct_checks :: proc(t: ^testing.T) { + log.debug("compiling C project") + { + switch pid := posix.fork(); pid { + case -1: + log.errorf("fork() failed: %s", posix.strerror()) + case 0: + c_compiler := posix.getenv("CC") + if c_compiler == nil { + c_compiler = "clang" + } + + posix.execlp(c_compiler, + c_compiler, #directory + "/structs/structs.c", "-o", #directory + "/structs/c_structs", nil) + posix.exit(69) + case: + if !wait_for(t, pid) { return } + log.debug("C code has been compiled!") + } + } + + log.debug("compiling Odin project") + { + switch pid := posix.fork(); pid { + case -1: + log.errorf("fork() failed: %s", posix.strerror()) + case 0: + posix.execlp(ODIN_ROOT + "/odin", + ODIN_ROOT + "/odin", "build", #directory + "/structs/structs.odin", "-out:" + #directory + "/structs/odin_structs", "-file", nil) + posix.exit(69) + case: + if !wait_for(t, pid) { return } + log.debug("Odin code has been compiled!") + } + } + + c_buf: [dynamic]byte + defer delete(c_buf) + c_out := get_output(t, &c_buf, #directory + "/structs/c_structs", nil) + + odin_buf: [dynamic]byte + defer delete(odin_buf) + odin_out := get_output(t, &odin_buf, #directory + "/structs/odin_structs", nil) + + testing.expectf(t, c_out == odin_out, "The C output and Odin output differ!\nC output:\n%s\n\n\n\nOdin Output:\n%s", c_out, odin_out) + + /* ----------- HELPERS ----------- */ + + wait_for :: proc(t: ^testing.T, pid: posix.pid_t) -> (ok: bool) { + log.debugf("waiting on pid %v", pid) + + waiting: for { + status: i32 + wpid := posix.waitpid(pid, &status, {}) + if !testing.expectf(t, wpid != -1, "waitpid() failure: %v", posix.strerror()) { + return false + } + + switch { + case posix.WIFEXITED(status): + ok = testing.expect_value(t, posix.WEXITSTATUS(status), 0) + break waiting + case posix.WIFSIGNALED(status): + log.errorf("child process raised: %v", posix.strsignal(posix.WTERMSIG(status))) + ok = false + break waiting + case: + log.errorf("unexpected status (this should never happen): %v", status) + ok = false + break waiting + } + } + + return + } + + get_output :: proc(t: ^testing.T, output: ^[dynamic]byte, cmd: ..cstring) -> (out_str: string) { + log.debugf("capturing output of: %v", cmd) + + pipe: [2]posix.FD + if !testing.expect_value(t, posix.pipe(&pipe), posix.result.OK) { + return + } + + switch pid := posix.fork(); pid { + case -1: + log.errorf("fork() failed: %s", posix.strerror()) + return + case 0: + posix.close(pipe[0]) + posix.dup2(pipe[1], 1) + posix.execv(cmd[0], raw_data(cmd[:])) + panic(string(posix.strerror())) + case: + posix.close(pipe[1]) + log.debugf("waiting on pid %v", pid) + + reader: for { + buf: [256]byte + switch read := posix.read(pipe[0], &buf[0], 256); { + case read < 0: + log.errorf("read output failed: %v", posix.strerror()) + return + case read == 0: + break reader + case: + append(output, ..buf[:read]) + } + } + + wait_for(t, pid) + + return string(output[:]) + } + } +} diff --git a/tests/core/sys/posix/structs/.gitignore b/tests/core/sys/posix/structs/.gitignore new file mode 100644 index 000000000..646eae0a2 --- /dev/null +++ b/tests/core/sys/posix/structs/.gitignore @@ -0,0 +1,2 @@ +c_structs +odin_structs diff --git a/tests/core/sys/posix/structs/structs.c b/tests/core/sys/posix/structs/structs.c new file mode 100644 index 000000000..7d8038fbb --- /dev/null +++ b/tests/core/sys/posix/structs/structs.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + printf("dirent %zu %zu\n", sizeof(struct dirent), _Alignof(struct dirent)); + printf("flock %zu %zu\n", sizeof(struct flock), _Alignof(struct flock)); + printf("glob_t %zu %zu\n", sizeof(glob_t), _Alignof(glob_t)); + printf("group %zu %zu\n", sizeof(struct group), _Alignof(struct group)); + printf("lconv %zu %zu\n", sizeof(struct lconv), _Alignof(struct lconv)); + + printf("pthread_t %zu %zu\n", sizeof(pthread_t), _Alignof(pthread_t)); + printf("pthread_attr_t %zu %zu\n", sizeof(pthread_attr_t), _Alignof(pthread_attr_t)); + printf("pthread_key_t %zu %zu\n", sizeof(pthread_key_t), _Alignof(pthread_key_t)); + + printf("sched_param %zu %zu\n", sizeof(struct sched_param), _Alignof(struct sched_param)); + + printf("termios %zu %zu\n", sizeof(struct termios), _Alignof(struct termios)); + + printf("in_addr %zu %zu\n", sizeof(struct in_addr), _Alignof(struct in_addr)); + printf("in6_addr %zu %zu\n", sizeof(struct in6_addr), _Alignof(struct in6_addr)); + printf("sockaddr_in %zu %zu\n", sizeof(struct sockaddr_in), _Alignof(struct sockaddr_in)); + printf("sockaddr_in6 %zu %zu\n", sizeof(struct sockaddr_in6), _Alignof(struct sockaddr_in6)); + printf("ipv6_mreq %zu %zu\n", sizeof(struct ipv6_mreq), _Alignof(struct ipv6_mreq)); + + printf("sockaddr_storage %zu %zu\n", sizeof(struct sockaddr_storage), _Alignof(struct sockaddr_storage)); + printf("msghdr %zu %zu\n", sizeof(struct msghdr), _Alignof(struct msghdr)); + printf("cmsghdr %zu %zu\n", sizeof(struct cmsghdr), _Alignof(struct cmsghdr)); + printf("linger %zu %zu\n", sizeof(struct linger), _Alignof(struct linger)); + + printf("hostent %zu %zu\n", sizeof(struct hostent), _Alignof(struct hostent)); + printf("netent %zu %zu\n", sizeof(struct netent), _Alignof(struct netent)); + printf("protoent %zu %zu\n", sizeof(struct protoent), _Alignof(struct protoent)); + printf("servent %zu %zu\n", sizeof(struct servent), _Alignof(struct servent)); + printf("addrinfo %zu %zu\n", sizeof(struct addrinfo), _Alignof(struct addrinfo)); + + printf("pollfd %zu %zu\n", sizeof(struct pollfd), _Alignof(struct pollfd)); + + printf("passwd %zu %zu\n", sizeof(struct passwd), _Alignof(struct passwd)); + + printf("shmid_ds %zu %zu\n", sizeof(struct shmid_ds), _Alignof(struct shmid_ds)); + printf("ipc_perm %zu %zu\n", sizeof(struct ipc_perm), _Alignof(struct ipc_perm)); + printf("msqid_ds %zu %zu\n", sizeof(struct msqid_ds), _Alignof(struct msqid_ds)); + + printf("rlimit %zu %zu\n", sizeof(struct rlimit), _Alignof(struct rlimit)); + printf("rusage %zu %zu\n", sizeof(struct rusage), _Alignof(struct rusage)); + + printf("sockaddr_un %zu %zu\n", sizeof(struct sockaddr_un), _Alignof(struct sockaddr_un)); + + printf("utsname %zu %zu\n", sizeof(struct utsname), _Alignof(struct utsname)); + + printf("tms %zu %zu\n", sizeof(struct tms), _Alignof(struct tms)); + + printf("sigaction %zu %zu\n", sizeof(struct sigaction), _Alignof(struct sigaction)); + printf("stack_t %zu %zu\n", sizeof(stack_t), _Alignof(stack_t)); + printf("siginfo_t %zu %zu\n", sizeof(siginfo_t), _Alignof(siginfo_t)); + + printf("fd_set %zu %zu\n", sizeof(fd_set), _Alignof(fd_set)); + + printf("iovec %zu %zu\n", sizeof(struct iovec), _Alignof(struct iovec)); + + printf("semid_ds %zu %zu\n", sizeof(struct semid_ds), _Alignof(struct semid_ds)); + printf("sembuf %zu %zu\n", sizeof(struct sembuf), _Alignof(struct sembuf)); + + printf("itimerval %zu %zu\n", sizeof(struct itimerval), _Alignof(struct itimerval)); + + printf("utimbuf %zu %zu\n", sizeof(struct utimbuf), _Alignof(struct utimbuf)); + + printf("wordexp_t %zu %zu\n", sizeof(wordexp_t), _Alignof(wordexp_t)); + + printf("time_t %zu %zu\n", sizeof(time_t), _Alignof(time_t)); + printf("timespec %zu %zu\n", sizeof(struct timespec), _Alignof(struct timespec)); + printf("clock_t %zu %zu\n", sizeof(clock_t), _Alignof(clock_t)); + + return 0; +} diff --git a/tests/core/sys/posix/structs/structs.odin b/tests/core/sys/posix/structs/structs.odin new file mode 100644 index 000000000..2663d1e30 --- /dev/null +++ b/tests/core/sys/posix/structs/structs.odin @@ -0,0 +1,74 @@ +package main + +import "core:fmt" +import "core:sys/posix" + +main :: proc() { + fmt.println("dirent", size_of(posix.dirent), align_of(posix.dirent)) + fmt.println("flock", size_of(posix.flock), align_of(posix.flock)) + fmt.println("glob_t", size_of(posix.glob_t), align_of(posix.glob_t)) + fmt.println("group", size_of(posix.group), align_of(posix.group)) + fmt.println("lconv", size_of(posix.lconv), align_of(posix.lconv)) + + fmt.println("pthread_t", size_of(posix.pthread_t), align_of(posix.pthread_t)) + fmt.println("pthread_attr_t", size_of(posix.pthread_attr_t), align_of(posix.pthread_attr_t)) + fmt.println("pthread_key_t", size_of(posix.pthread_key_t), align_of(posix.pthread_key_t)) + + fmt.println("sched_param", size_of(posix.sched_param), align_of(posix.sched_param)) + + fmt.println("termios", size_of(posix.termios), align_of(posix.termios)) + + fmt.println("in_addr", size_of(posix.in_addr), align_of(posix.in_addr)) + fmt.println("in6_addr", size_of(posix.in6_addr), align_of(posix.in6_addr)) + fmt.println("sockaddr_in", size_of(posix.sockaddr_in), align_of(posix.sockaddr_in)) + fmt.println("sockaddr_in6", size_of(posix.sockaddr_in6), align_of(posix.sockaddr_in6)) + fmt.println("ipv6_mreq", size_of(posix.ipv6_mreq), align_of(posix.ipv6_mreq)) + + fmt.println("sockaddr_storage", size_of(posix.sockaddr_storage), align_of(posix.sockaddr_storage)) + fmt.println("msghdr", size_of(posix.msghdr), align_of(posix.msghdr)) + fmt.println("cmsghdr", size_of(posix.cmsghdr), align_of(posix.cmsghdr)) + fmt.println("linger", size_of(posix.linger), align_of(posix.linger)) + + fmt.println("hostent", size_of(posix.hostent), align_of(posix.hostent)) + fmt.println("netent", size_of(posix.netent), align_of(posix.netent)) + fmt.println("protoent", size_of(posix.protoent), align_of(posix.protoent)) + fmt.println("servent", size_of(posix.servent), align_of(posix.servent)) + fmt.println("addrinfo", size_of(posix.addrinfo), align_of(posix.addrinfo)) + + fmt.println("pollfd", size_of(posix.pollfd), align_of(posix.pollfd)) + fmt.println("passwd", size_of(posix.passwd), align_of(posix.passwd)) + + fmt.println("shmid_ds", size_of(posix.shmid_ds), align_of(posix.shmid_ds)) + fmt.println("ipc_perm", size_of(posix.ipc_perm), align_of(posix.ipc_perm)) + fmt.println("msqid_ds", size_of(posix.msqid_ds), align_of(posix.msqid_ds)) + + fmt.println("rlimit", size_of(posix.rlimit), align_of(posix.rlimit)) + fmt.println("rusage", size_of(posix.rusage), align_of(posix.rusage)) + + fmt.println("sockaddr_un", size_of(posix.sockaddr_un), align_of(posix.sockaddr_un)) + + fmt.println("utsname", size_of(posix.utsname), align_of(posix.utsname)) + + fmt.println("tms", size_of(posix.tms), align_of(posix.tms)) + + fmt.println("sigaction", size_of(posix.sigaction_t), align_of(posix.sigaction_t)) + fmt.println("stack_t", size_of(posix.stack_t), align_of(posix.stack_t)) + fmt.println("siginfo_t", size_of(posix.siginfo_t), align_of(posix.siginfo_t)) + + fmt.println("fd_set", size_of(posix.fd_set), align_of(posix.fd_set)) + + fmt.println("iovec", size_of(posix.iovec), align_of(posix.iovec)) + + fmt.println("semid_ds", size_of(posix.semid_ds), align_of(posix.semid_ds)) + fmt.println("sembuf", size_of(posix.sembuf), align_of(posix.sembuf)) + + fmt.println("itimerval", size_of(posix.itimerval), align_of(posix.itimerval)) + + fmt.println("utimbuf", size_of(posix.utimbuf), align_of(posix.utimbuf)) + + fmt.println("wordexp_t", size_of(posix.wordexp_t), align_of(posix.wordexp_t)) + + fmt.println("time_t", size_of(posix.time_t), align_of(posix.time_t)) + fmt.println("timespec", size_of(posix.timespec), align_of(posix.timespec)) + fmt.println("clock_t", size_of(posix.clock_t), align_of(posix.clock_t)) +} -- cgit v1.2.3 From ca6ef95b038f3eb443971240de73924a721485cc Mon Sep 17 00:00:00 2001 From: Laytan Date: Thu, 15 Aug 2024 20:39:35 +0200 Subject: add support for linux_riscv64 and freestanding_riscv64 --- .github/workflows/ci.yml | 50 +++ base/runtime/entry_unix.odin | 3 + base/runtime/entry_unix_no_crt_riscv64.asm | 10 + base/runtime/os_specific_linux.odin | 2 + .../crypto/_chacha20/simd128/chacha20_simd128.odin | 2 +- core/net/socket_linux.odin | 4 +- core/os/os_linux.odin | 19 ++ core/sys/info/cpu_linux_riscv64.odin | 46 +++ core/sys/info/cpu_riscv64.odin | 16 + core/sys/info/sysinfo.odin | 2 +- core/sys/linux/bits.odin | 14 +- core/sys/linux/sys.odin | 54 +-- core/sys/linux/syscall_riscv64.odin | 334 ++++++++++++++++++ core/sys/linux/types.odin | 48 ++- core/sys/unix/syscalls_linux.odin | 380 +++++++++++++++++++-- misc/featuregen/README.md | 4 +- misc/featuregen/build_featuregen.sh | 5 + misc/featuregen/featuregen.py | 19 +- src/build_settings.cpp | 20 +- src/build_settings_microarch.cpp | 102 ++++-- src/check_builtin.cpp | 5 + src/checker.cpp | 1 + src/linker.cpp | 29 +- src/llvm_abi.cpp | 269 ++++++++++++++- src/llvm_backend.cpp | 31 +- src/llvm_backend_general.cpp | 8 +- src/llvm_backend_proc.cpp | 25 ++ src/main.cpp | 9 + 28 files changed, 1395 insertions(+), 116 deletions(-) create mode 100644 base/runtime/entry_unix_no_crt_riscv64.asm create mode 100644 core/sys/info/cpu_linux_riscv64.odin create mode 100644 core/sys/info/cpu_riscv64.odin create mode 100644 core/sys/linux/syscall_riscv64.odin create mode 100755 misc/featuregen/build_featuregen.sh (limited to 'src/check_builtin.cpp') diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb5ad0d27..455a451e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -220,3 +220,53 @@ jobs: run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat odin check examples/all -strict-style -target:windows_i386 + + build_linux_riscv64: + runs-on: ubuntu-latest + name: Linux riscv64 (emulated) Build, Check and Test + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + + - name: Download LLVM (Linux) + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 18 + echo "/usr/lib/llvm-18/bin" >> $GITHUB_PATH + + - name: Build Odin + run: ./build_odin.sh release + + - name: Odin version + run: ./odin version + + - name: Odin report + run: ./odin report + + - name: Compile needed Vendor + run: | + make -C vendor/stb/src + make -C vendor/cgltf/src + make -C vendor/miniaudio/src + + - name: Odin check + run: ./odin check examples/all -target:linux_riscv64 -vet -strict-style -disallow-do + + - name: Install riscv64 toolchain and qemu + run: sudo apt-get install -y qemu-user qemu-user-static gcc-12-riscv64-linux-gnu libc6-riscv64-cross + + - name: Odin run + run: ./odin run examples/demo -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + + - name: Odin run -debug + run: ./odin run examples/demo -debug -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + + - name: Normal Core library tests + run: ./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + + - name: Optimized Core library tests + run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + + - name: Internals tests + run: ./odin test tests/internal -all-packages -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" diff --git a/base/runtime/entry_unix.odin b/base/runtime/entry_unix.odin index 7d7252625..5dfd37f99 100644 --- a/base/runtime/entry_unix.odin +++ b/base/runtime/entry_unix.odin @@ -34,6 +34,9 @@ when ODIN_BUILD_MODE == .Dynamic { } else when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 { @require foreign import entry "entry_unix_no_crt_darwin_arm64.asm" SYS_exit :: 1 + } else when ODIN_ARCH == .riscv64 { + @require foreign import entry "entry_unix_no_crt_riscv64.asm" + SYS_exit :: 93 } @(link_name="_start_odin", linkage="strong", require) _start_odin :: proc "c" (argc: i32, argv: [^]cstring) -> ! { diff --git a/base/runtime/entry_unix_no_crt_riscv64.asm b/base/runtime/entry_unix_no_crt_riscv64.asm new file mode 100644 index 000000000..756515b72 --- /dev/null +++ b/base/runtime/entry_unix_no_crt_riscv64.asm @@ -0,0 +1,10 @@ +.text + +.globl _start + +_start: + ld a0, 0(sp) + addi a1, sp, 8 + addi sp, sp, ~15 + call _start_odin + ebreak diff --git a/base/runtime/os_specific_linux.odin b/base/runtime/os_specific_linux.odin index a944ba309..146e647fb 100644 --- a/base/runtime/os_specific_linux.odin +++ b/base/runtime/os_specific_linux.odin @@ -12,6 +12,8 @@ _stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) { SYS_write :: uintptr(4) } else when ODIN_ARCH == .arm32 { SYS_write :: uintptr(4) + } else when ODIN_ARCH == .riscv64 { + SYS_write :: uintptr(64) } stderr :: 2 diff --git a/core/crypto/_chacha20/simd128/chacha20_simd128.odin b/core/crypto/_chacha20/simd128/chacha20_simd128.odin index 4cab3c5e8..2f91ac52a 100644 --- a/core/crypto/_chacha20/simd128/chacha20_simd128.odin +++ b/core/crypto/_chacha20/simd128/chacha20_simd128.odin @@ -3,7 +3,7 @@ package chacha20_simd128 import "base:intrinsics" import "core:crypto/_chacha20" import "core:simd" -import "core:sys/info" +@(require) import "core:sys/info" // Portable 128-bit `core:simd` implementation. // diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index dce428685..52f328814 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -33,8 +33,8 @@ Socket_Option :: enum c.int { Linger = c.int(linux.Socket_Option.LINGER), Receive_Buffer_Size = c.int(linux.Socket_Option.RCVBUF), Send_Buffer_Size = c.int(linux.Socket_Option.SNDBUF), - Receive_Timeout = c.int(linux.Socket_Option.RCVTIMEO_NEW), - Send_Timeout = c.int(linux.Socket_Option.SNDTIMEO_NEW), + Receive_Timeout = c.int(linux.Socket_Option.RCVTIMEO), + Send_Timeout = c.int(linux.Socket_Option.SNDTIMEO), } // Wrappers and unwrappers for system-native types diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 0fcd1a21a..f1b3720c6 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -284,6 +284,25 @@ when ODIN_ARCH == .arm64 { _reserved: [2]i32, } #assert(size_of(OS_Stat) == 128) +} else when ODIN_ARCH == .riscv64 { + OS_Stat :: struct { + device_id: u64, + serial: u64, + mode: u32, + nlink: u32, + uid: u32, + gid: u32, + rdev: u64, + _: u64, + size: i64, + block_size: i32, + _: i32, + blocks: i64, + last_access: Unix_File_Time, + modified: Unix_File_Time, + status_change: Unix_File_Time, + _: [3]uint, + } } else { OS_Stat :: struct { device_id: u64, // ID of device containing file diff --git a/core/sys/info/cpu_linux_riscv64.odin b/core/sys/info/cpu_linux_riscv64.odin new file mode 100644 index 000000000..0f109e7ba --- /dev/null +++ b/core/sys/info/cpu_linux_riscv64.odin @@ -0,0 +1,46 @@ +//+build riscv64 +//+build linux +package sysinfo + +import "base:intrinsics" + +import "core:sys/linux" + +@(init, private) +init_cpu_features :: proc() { + fd, err := linux.open("/proc/self/auxv", {}) + if err != .NONE { return } + defer linux.close(fd) + + // This is probably enough right? + buf: [4096]byte + n, rerr := linux.read(fd, buf[:]) + if rerr != .NONE || n == 0 { return } + + ulong :: u64 + AT_HWCAP :: 16 + + // TODO: using these we could get more information than just the basics. + // AT_HWCAP2 :: 26 + // AT_HWCAP3 :: 29 + // AT_HWCAP4 :: 30 + + auxv := buf[:n] + for len(auxv) >= size_of(ulong)*2 { + key := intrinsics.unaligned_load((^ulong)(&auxv[0])) + val := intrinsics.unaligned_load((^ulong)(&auxv[size_of(ulong)])) + auxv = auxv[2*size_of(ulong):] + + if key != AT_HWCAP { + continue + } + + cpu_features = transmute(CPU_Features)(val) + break + } +} + +@(init, private) +init_cpu_name :: proc() { + cpu_name = "RISCV64" +} diff --git a/core/sys/info/cpu_riscv64.odin b/core/sys/info/cpu_riscv64.odin new file mode 100644 index 000000000..754110911 --- /dev/null +++ b/core/sys/info/cpu_riscv64.odin @@ -0,0 +1,16 @@ +package sysinfo + +CPU_Feature :: enum u64 { + I = 'I' - 'A', // Base features, don't think this is ever not here. + M = 'M' - 'A', // Integer multiplication and division, currently required by Odin. + A = 'A' - 'A', // Atomics. + F = 'F' - 'A', // Single precision floating point, currently required by Odin. + D = 'D' - 'A', // Double precision floating point, currently required by Odin. + C = 'C' - 'A', // Compressed instructions. + V = 'V' - 'A', // Vector operations. +} + +CPU_Features :: distinct bit_set[CPU_Feature; u64] + +cpu_features: Maybe(CPU_Features) +cpu_name: Maybe(string) diff --git a/core/sys/info/sysinfo.odin b/core/sys/info/sysinfo.odin index f0262f317..f624a1718 100644 --- a/core/sys/info/sysinfo.odin +++ b/core/sys/info/sysinfo.odin @@ -1,6 +1,6 @@ package sysinfo -when !(ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || ODIN_ARCH == .arm32 || ODIN_ARCH == .arm64) { +when !(ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || ODIN_ARCH == .arm32 || ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64) { #assert(false, "This package is unsupported on this architecture.") } diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin index b8ec3c133..f78891bc8 100644 --- a/core/sys/linux/bits.odin +++ b/core/sys/linux/bits.odin @@ -1343,14 +1343,16 @@ Socket_Option :: enum { RESERVE_MEM = 73, TXREHASH = 74, RCVMARK = 75, - // Hardcoded 64-bit Time. It's time to move on. - TIMESTAMP = TIMESTAMP_NEW, - TIMESTAMPNS = TIMESTAMPNS_NEW, - TIMESTAMPING = TIMESTAMPING_NEW, - RCVTIMEO = RCVTIMEO_NEW, - SNDTIMEO = SNDTIMEO_NEW, + TIMESTAMP = TIMESTAMP_OLD when _SOCKET_OPTION_OLD else TIMESTAMP_NEW, + TIMESTAMPNS = TIMESTAMPNS_OLD when _SOCKET_OPTION_OLD else TIMESTAMPNS_NEW, + TIMESTAMPING = TIMESTAMPING_OLD when _SOCKET_OPTION_OLD else TIMESTAMPING_NEW, + RCVTIMEO = RCVTIMEO_OLD when _SOCKET_OPTION_OLD else RCVTIMEO_NEW, + SNDTIMEO = SNDTIMEO_OLD when _SOCKET_OPTION_OLD else SNDTIMEO_NEW, } +@(private) +_SOCKET_OPTION_OLD :: size_of(rawptr) == 8 /* || size_of(time_t) == size_of(__kernel_long_t) */ + Socket_UDP_Option :: enum { CORK = 1, ENCAP = 100, diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin index f4f609ab9..a6d4f723d 100644 --- a/core/sys/linux/sys.odin +++ b/core/sys/linux/sys.odin @@ -39,7 +39,7 @@ write :: proc "contextless" (fd: Fd, buf: []u8) -> (int, Errno) { On ARM64 available since Linux 2.6.16. */ open :: proc "contextless" (name: cstring, flags: Open_Flags, mode: Mode = {}) -> (Fd, Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_openat, AT_FDCWD, transmute(uintptr) name, transmute(u32) flags, transmute(u32) mode) return errno_unwrap(ret, Fd) } else { @@ -68,7 +68,7 @@ close :: proc "contextless" (fd: Fd) -> (Errno) { */ stat :: proc "contextless" (filename: cstring, stat: ^Stat) -> (Errno) { when size_of(int) == 8 { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_fstatat, AT_FDCWD, cast(rawptr) filename, stat, 0) return Errno(-ret) } else { @@ -111,7 +111,7 @@ fstat :: proc "contextless" (fd: Fd, stat: ^Stat) -> (Errno) { */ lstat :: proc "contextless" (filename: cstring, stat: ^Stat) -> (Errno) { when size_of(int) == 8 { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { return fstatat(AT_FDCWD, filename, stat, {.SYMLINK_NOFOLLOW}) } else { ret := syscall(SYS_lstat, cast(rawptr) filename, stat) @@ -128,7 +128,7 @@ lstat :: proc "contextless" (filename: cstring, stat: ^Stat) -> (Errno) { Available since Linux 2.2. */ poll :: proc "contextless" (fds: []Poll_Fd, timeout: i32) -> (i32, Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { seconds := cast(uint) timeout / 1000 nanoseconds := cast(uint) (timeout % 1000) * 1_000_000 timeout_spec := Time_Spec{seconds, nanoseconds} @@ -291,7 +291,7 @@ writev :: proc "contextless" (fd: Fd, iov: []IO_Vec) -> (int, Errno) { For ARM64 available since Linux 2.6.16. */ access :: proc "contextless" (name: cstring, mode: Mode = F_OK) -> (Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_faccessat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode) return Errno(-ret) } else { @@ -407,7 +407,7 @@ dup :: proc "contextless" (fd: Fd) -> (Fd, Errno) { On ARM64 available since Linux 2.6.27. */ dup2 :: proc "contextless" (old: Fd, new: Fd) -> (Fd, Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_dup3, old, new, 0) return errno_unwrap(ret, Fd) } else { @@ -422,7 +422,7 @@ dup2 :: proc "contextless" (old: Fd, new: Fd) -> (Fd, Errno) { On ARM64 available since Linux 2.6.16. */ pause :: proc "contextless" () { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { syscall(SYS_ppoll, 0, 0, 0, 0) } else { syscall(SYS_pause) @@ -452,7 +452,7 @@ getitimer :: proc "contextless" (which: ITimer_Which, cur: ^ITimer_Val) -> (Errn Available since Linux 1.0. */ alarm :: proc "contextless" (seconds: u32) -> u32 { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { new := ITimer_Val { value = { seconds = cast(int) seconds } } old := ITimer_Val {} syscall(SYS_setitimer, ITimer_Which.REAL, &new, &old) @@ -765,7 +765,7 @@ getsockopt :: proc { Available since Linux 1.0. */ fork :: proc "contextless" () -> (Pid, Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_clone, u64(Signal.SIGCHLD), cast(rawptr) nil, cast(rawptr) nil, cast(rawptr) nil, u64(0)) return errno_unwrap(ret, Pid) } else { @@ -779,7 +779,7 @@ fork :: proc "contextless" () -> (Pid, Errno) { Available since Linux 2.2. */ vfork :: proc "contextless" () -> Pid { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return Pid(syscall(SYS_vfork)) } else { return Pid(syscall(SYS_clone, Signal.SIGCHLD)) @@ -792,7 +792,7 @@ vfork :: proc "contextless" () -> Pid { On ARM64 available since Linux 3.19. */ execve :: proc "contextless" (name: cstring, argv: [^]cstring, envp: [^]cstring) -> (Errno) { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { ret := syscall(SYS_execve, cast(rawptr) name, cast(rawptr) argv, cast(rawptr) envp) return Errno(-ret) } else { @@ -1193,7 +1193,7 @@ fchdir :: proc "contextless" (fd: Fd) -> (Errno) { On ARM64 available since Linux 2.6.16. */ rename :: proc "contextless" (old: cstring, new: cstring) -> (Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_renameat, AT_FDCWD, cast(rawptr) old, AT_FDCWD, cast(rawptr) new) return Errno(-ret) } else { @@ -1208,7 +1208,7 @@ rename :: proc "contextless" (old: cstring, new: cstring) -> (Errno) { On ARM64 available since Linux 2.6.16. */ mkdir :: proc "contextless" (name: cstring, mode: Mode) -> (Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_mkdirat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode) return Errno(-ret) } else { @@ -1223,7 +1223,7 @@ mkdir :: proc "contextless" (name: cstring, mode: Mode) -> (Errno) { On ARM64 available since Linux 2.6.16. */ rmdir :: proc "contextless" (name: cstring) -> (Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_unlinkat, AT_FDCWD, cast(rawptr) name, transmute(i32) FD_Flags{.REMOVEDIR}) return Errno(-ret) } else { @@ -1238,7 +1238,7 @@ rmdir :: proc "contextless" (name: cstring) -> (Errno) { On ARM64 available since Linux 2.6.16. */ creat :: proc "contextless" (name: cstring, mode: Mode) -> (Fd, Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { return openat(AT_FDCWD, name, {.CREAT, .WRONLY,.TRUNC}, mode) } else { ret := syscall(SYS_creat, cast(rawptr) name, transmute(u32) mode) @@ -1252,7 +1252,7 @@ creat :: proc "contextless" (name: cstring, mode: Mode) -> (Fd, Errno) { On ARM64 available since Linux 2.6.16. */ link :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_linkat, AT_FDCWD, cast(rawptr) target, AT_FDCWD, cast(rawptr) linkpath, 0) return Errno(-ret) } else { @@ -1267,7 +1267,7 @@ link :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) { On ARM64 available since Linux 2.6.16. */ unlink :: proc "contextless" (name: cstring) -> (Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_unlinkat, AT_FDCWD, cast(rawptr) name, 0) return Errno(-ret) } else { @@ -1282,7 +1282,7 @@ unlink :: proc "contextless" (name: cstring) -> (Errno) { On arm64 available since Linux 2.6.16. */ symlink :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_symlinkat, cast(rawptr) target, AT_FDCWD, cast(rawptr) linkpath) return Errno(-ret) } else { @@ -1297,7 +1297,7 @@ symlink :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) { On arm64 available since Linux 2.6.16. */ readlink :: proc "contextless" (name: cstring, buf: []u8) -> (int, Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_readlinkat, AT_FDCWD, cast(rawptr) name, raw_data(buf), len(buf)) return errno_unwrap(ret, int) } else { @@ -1312,7 +1312,7 @@ readlink :: proc "contextless" (name: cstring, buf: []u8) -> (int, Errno) { On ARM64 available since Linux 2.6.16. */ chmod :: proc "contextless" (name: cstring, mode: Mode) -> (Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_fchmodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode) return Errno(-ret) } else { @@ -1340,7 +1340,7 @@ chown :: proc "contextless" (name: cstring, uid: Uid, gid: Gid) -> (Errno) { when size_of(int) == 4 { ret := syscall(SYS_chown32, cast(rawptr) name, uid, gid) return Errno(-ret) - } else when ODIN_ARCH == .arm64 { + } else when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_fchownat, AT_FDCWD, cast(rawptr) name, uid, gid, 0) return Errno(-ret) } else { @@ -1374,7 +1374,7 @@ lchown :: proc "contextless" (name: cstring, uid: Uid, gid: Gid) -> (Errno) { when size_of(int) == 4 { ret := syscall(SYS_lchown32, cast(rawptr) name, uid, gid) return Errno(-ret) - } else when ODIN_ARCH == .arm64 { + } else when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_fchownat, AT_FDCWD, cast(rawptr) name, uid, gid, transmute(i32) FD_Flags{.SYMLINK_NOFOLLOW}) return Errno(-ret) } else { @@ -1727,7 +1727,7 @@ getppid :: proc "contextless" () -> Pid { Available since Linux 1.0. */ getpgrp :: proc "contextless" () -> (Pid, Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_getpgid, 0) return errno_unwrap(ret, Pid) } else { @@ -1950,7 +1950,7 @@ sigaltstack :: proc "contextless" (stack: ^Sig_Stack, old_stack: ^Sig_Stack) -> On ARM64 available since Linux 2.6.16. */ mknod :: proc "contextless" (name: cstring, mode: Mode, dev: Dev) -> (Errno) { - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { ret := syscall(SYS_mknodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode, dev) return Errno(-ret) } else { @@ -2207,7 +2207,7 @@ gettid :: proc "contextless" () -> Pid { Available since Linux 1.0. */ time :: proc "contextless" (tloc: ^uint) -> (Errno) { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { ret := syscall(SYS_time, tloc) return Errno(-ret) } else { @@ -2335,7 +2335,7 @@ futex :: proc{ Available since Linux 2.6. */ epoll_create :: proc(size: i32 = 1) -> (Fd, Errno) { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { ret := syscall(SYS_epoll_create, i32(1)) return errno_unwrap(ret, Fd) } else { @@ -2433,7 +2433,7 @@ exit_group :: proc "contextless" (code: i32) -> ! { Available since Linux 2.6. */ epoll_wait :: proc(epfd: Fd, events: [^]EPoll_Event, count: i32, timeout: i32) -> (i32, Errno) { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { ret := syscall(SYS_epoll_wait, epfd, events, count, timeout) return errno_unwrap(ret, i32) } else { diff --git a/core/sys/linux/syscall_riscv64.odin b/core/sys/linux/syscall_riscv64.odin new file mode 100644 index 000000000..ce374312e --- /dev/null +++ b/core/sys/linux/syscall_riscv64.odin @@ -0,0 +1,334 @@ +//+build riscv64 +package linux + +// https://github.com/riscv-collab/riscv-gnu-toolchain/blob/master/linux-headers/include/asm-generic/unistd.h + +SYS_io_setup :: uintptr(0) +SYS_io_destroy :: uintptr(1) +SYS_io_submit :: uintptr(2) +SYS_io_cancel :: uintptr(3) +SYS_io_getevents :: uintptr(4) +SYS_setxattr :: uintptr(5) +SYS_lsetxattr :: uintptr(6) +SYS_fsetxattr :: uintptr(7) +SYS_getxattr :: uintptr(8) +SYS_lgetxattr :: uintptr(9) +SYS_fgetxattr :: uintptr(10) +SYS_listxattr :: uintptr(11) +SYS_llistxattr :: uintptr(12) +SYS_flistxattr :: uintptr(13) +SYS_removexattr :: uintptr(14) +SYS_lremovexattr :: uintptr(15) +SYS_fremovexattr :: uintptr(16) +SYS_getcwd :: uintptr(17) +SYS_lookup_dcookie :: uintptr(18) +SYS_eventfd2 :: uintptr(19) +SYS_epoll_create1 :: uintptr(20) +SYS_epoll_ctl :: uintptr(21) +SYS_epoll_pwait :: uintptr(22) +SYS_dup :: uintptr(23) +SYS_dup3 :: uintptr(24) +SYS_fcntl :: uintptr(25) +SYS_inotify_init1 :: uintptr(26) +SYS_inotify_add_watch :: uintptr(27) +SYS_inotify_rm_watch :: uintptr(28) +SYS_ioctl :: uintptr(29) +SYS_ioprio_set :: uintptr(30) +SYS_ioprio_get :: uintptr(31) +SYS_flock :: uintptr(32) +SYS_mknodat :: uintptr(33) +SYS_mkdirat :: uintptr(34) +SYS_unlinkat :: uintptr(35) +SYS_symlinkat :: uintptr(36) +SYS_linkat :: uintptr(37) +SYS_renameat :: uintptr(38) +SYS_umount2 :: uintptr(39) +SYS_mount :: uintptr(40) +SYS_pivot_root :: uintptr(41) +SYS_nfsservctl :: uintptr(42) +SYS_statfs :: uintptr(43) +SYS_fstatfs :: uintptr(44) +SYS_truncate :: uintptr(45) +SYS_ftruncate :: uintptr(46) +SYS_fallocate :: uintptr(47) +SYS_faccessat :: uintptr(48) +SYS_chdir :: uintptr(49) +SYS_fchdir :: uintptr(50) +SYS_chroot :: uintptr(51) +SYS_fchmod :: uintptr(52) +SYS_fchmodat :: uintptr(53) +SYS_fchownat :: uintptr(54) +SYS_fchown :: uintptr(55) +SYS_openat :: uintptr(56) +SYS_close :: uintptr(57) +SYS_vhangup :: uintptr(58) +SYS_pipe2 :: uintptr(59) +SYS_quotactl :: uintptr(60) +SYS_getdents64 :: uintptr(61) +SYS_lseek :: uintptr(62) +SYS_read :: uintptr(63) +SYS_write :: uintptr(64) +SYS_readv :: uintptr(65) +SYS_writev :: uintptr(66) +SYS_pread64 :: uintptr(67) +SYS_pwrite64 :: uintptr(68) +SYS_preadv :: uintptr(69) +SYS_pwritev :: uintptr(70) +SYS_sendfile :: uintptr(71) +SYS_pselect6 :: uintptr(72) +SYS_ppoll :: uintptr(73) +SYS_signalfd4 :: uintptr(74) +SYS_vmsplice :: uintptr(75) +SYS_splice :: uintptr(76) +SYS_tee :: uintptr(77) +SYS_readlinkat :: uintptr(78) +SYS_fstatat :: uintptr(79) +SYS_fstat :: uintptr(80) +SYS_sync :: uintptr(81) +SYS_fsync :: uintptr(82) +SYS_fdatasync :: uintptr(83) +SYS_sync_file_range2 :: uintptr(84) +SYS_sync_file_range :: uintptr(84) +SYS_timerfd_create :: uintptr(85) +SYS_timerfd_settime :: uintptr(86) +SYS_timerfd_gettime :: uintptr(87) +SYS_utimensat :: uintptr(88) +SYS_acct :: uintptr(89) +SYS_capget :: uintptr(90) +SYS_capset :: uintptr(91) +SYS_personality :: uintptr(92) +SYS_exit :: uintptr(93) +SYS_exit_group :: uintptr(94) +SYS_waitid :: uintptr(95) +SYS_set_tid_address :: uintptr(96) +SYS_unshare :: uintptr(97) +SYS_futex :: uintptr(98) +SYS_set_robust_list :: uintptr(99) +SYS_get_robust_list :: uintptr(100) +SYS_nanosleep :: uintptr(101) +SYS_getitimer :: uintptr(102) +SYS_setitimer :: uintptr(103) +SYS_kexec_load :: uintptr(104) +SYS_init_module :: uintptr(105) +SYS_delete_module :: uintptr(106) +SYS_timer_create :: uintptr(107) +SYS_timer_gettime :: uintptr(108) +SYS_timer_getoverrun :: uintptr(109) +SYS_timer_settime :: uintptr(110) +SYS_timer_delete :: uintptr(111) +SYS_clock_settime :: uintptr(112) +SYS_clock_gettime :: uintptr(113) +SYS_clock_getres :: uintptr(114) +SYS_clock_nanosleep :: uintptr(115) +SYS_syslog :: uintptr(116) +SYS_ptrace :: uintptr(117) +SYS_sched_setparam :: uintptr(118) +SYS_sched_setscheduler :: uintptr(119) +SYS_sched_getscheduler :: uintptr(120) +SYS_sched_getparam :: uintptr(121) +SYS_sched_setaffinity :: uintptr(122) +SYS_sched_getaffinity :: uintptr(123) +SYS_sched_yield :: uintptr(124) +SYS_sched_get_priority_max :: uintptr(125) +SYS_sched_get_priority_min :: uintptr(126) +SYS_sched_rr_get_interval :: uintptr(127) +SYS_restart_syscall :: uintptr(128) +SYS_kill :: uintptr(129) +SYS_tkill :: uintptr(130) +SYS_tgkill :: uintptr(131) +SYS_sigaltstack :: uintptr(132) +SYS_rt_sigsuspend :: uintptr(133) +SYS_rt_sigaction :: uintptr(134) +SYS_rt_sigprocmask :: uintptr(135) +SYS_rt_sigpending :: uintptr(136) +SYS_rt_sigtimedwait :: uintptr(137) +SYS_rt_sigqueueinfo :: uintptr(138) +SYS_rt_sigreturn :: uintptr(139) +SYS_setpriority :: uintptr(140) +SYS_getpriority :: uintptr(141) +SYS_reboot :: uintptr(142) +SYS_setregid :: uintptr(143) +SYS_setgid :: uintptr(144) +SYS_setreuid :: uintptr(145) +SYS_setuid :: uintptr(146) +SYS_setresuid :: uintptr(147) +SYS_getresuid :: uintptr(148) +SYS_setresgid :: uintptr(149) +SYS_getresgid :: uintptr(150) +SYS_setfsuid :: uintptr(151) +SYS_setfsgid :: uintptr(152) +SYS_times :: uintptr(153) +SYS_setpgid :: uintptr(154) +SYS_getpgid :: uintptr(155) +SYS_getsid :: uintptr(156) +SYS_setsid :: uintptr(157) +SYS_getgroups :: uintptr(158) +SYS_setgroups :: uintptr(159) +SYS_uname :: uintptr(160) +SYS_sethostname :: uintptr(161) +SYS_setdomainname :: uintptr(162) +SYS_getrlimit :: uintptr(163) +SYS_setrlimit :: uintptr(164) +SYS_getrusage :: uintptr(165) +SYS_umask :: uintptr(166) +SYS_prctl :: uintptr(167) +SYS_getcpu :: uintptr(168) +SYS_gettimeofday :: uintptr(169) +SYS_settimeofday :: uintptr(170) +SYS_adjtimex :: uintptr(171) +SYS_getpid :: uintptr(172) +SYS_getppid :: uintptr(173) +SYS_getuid :: uintptr(174) +SYS_geteuid :: uintptr(175) +SYS_getgid :: uintptr(176) +SYS_getegid :: uintptr(177) +SYS_gettid :: uintptr(178) +SYS_sysinfo :: uintptr(179) +SYS_mq_open :: uintptr(180) +SYS_mq_unlink :: uintptr(181) +SYS_mq_timedsend :: uintptr(182) +SYS_mq_timedreceive :: uintptr(183) +SYS_mq_notify :: uintptr(184) +SYS_mq_getsetattr :: uintptr(185) +SYS_msgget :: uintptr(186) +SYS_msgctl :: uintptr(187) +SYS_msgrcv :: uintptr(188) +SYS_msgsnd :: uintptr(189) +SYS_semget :: uintptr(190) +SYS_semctl :: uintptr(191) +SYS_semtimedop :: uintptr(192) +SYS_semop :: uintptr(193) +SYS_shmget :: uintptr(194) +SYS_shmctl :: uintptr(195) +SYS_shmat :: uintptr(196) +SYS_shmdt :: uintptr(197) +SYS_socket :: uintptr(198) +SYS_socketpair :: uintptr(199) +SYS_bind :: uintptr(200) +SYS_listen :: uintptr(201) +SYS_accept :: uintptr(202) +SYS_connect :: uintptr(203) +SYS_getsockname :: uintptr(204) +SYS_getpeername :: uintptr(205) +SYS_sendto :: uintptr(206) +SYS_recvfrom :: uintptr(207) +SYS_setsockopt :: uintptr(208) +SYS_getsockopt :: uintptr(209) +SYS_shutdown :: uintptr(210) +SYS_sendmsg :: uintptr(211) +SYS_recvmsg :: uintptr(212) +SYS_readahead :: uintptr(213) +SYS_brk :: uintptr(214) +SYS_munmap :: uintptr(215) +SYS_mremap :: uintptr(216) +SYS_add_key :: uintptr(217) +SYS_request_key :: uintptr(218) +SYS_keyctl :: uintptr(219) +SYS_clone :: uintptr(220) +SYS_execve :: uintptr(221) +SYS_mmap :: uintptr(222) +SYS_fadvise64 :: uintptr(223) +SYS_swapon :: uintptr(224) +SYS_swapoff :: uintptr(225) +SYS_mprotect :: uintptr(226) +SYS_msync :: uintptr(227) +SYS_mlock :: uintptr(228) +SYS_munlock :: uintptr(229) +SYS_mlockall :: uintptr(230) +SYS_munlockall :: uintptr(231) +SYS_mincore :: uintptr(232) +SYS_madvise :: uintptr(233) +SYS_remap_file_pages :: uintptr(234) +SYS_mbind :: uintptr(235) +SYS_get_mempolicy :: uintptr(236) +SYS_set_mempolicy :: uintptr(237) +SYS_migrate_pages :: uintptr(238) +SYS_move_pages :: uintptr(239) +SYS_rt_tgsigqueueinfo :: uintptr(240) +SYS_perf_event_open :: uintptr(241) +SYS_accept4 :: uintptr(242) +SYS_recvmmsg :: uintptr(243) +SYS_wait4 :: uintptr(260) +SYS_prlimit64 :: uintptr(261) +SYS_fanotify_init :: uintptr(262) +SYS_fanotify_mark :: uintptr(263) +SYS_name_to_handle_at :: uintptr(264) +SYS_open_by_handle_at :: uintptr(265) +SYS_clock_adjtime :: uintptr(266) +SYS_syncfs :: uintptr(267) +SYS_setns :: uintptr(268) +SYS_sendmmsg :: uintptr(269) +SYS_process_vm_readv :: uintptr(270) +SYS_process_vm_writev :: uintptr(271) +SYS_kcmp :: uintptr(272) +SYS_finit_module :: uintptr(273) +SYS_sched_setattr :: uintptr(274) +SYS_sched_getattr :: uintptr(275) +SYS_renameat2 :: uintptr(276) +SYS_seccomp :: uintptr(277) +SYS_getrandom :: uintptr(278) +SYS_memfd_create :: uintptr(279) +SYS_bpf :: uintptr(280) +SYS_execveat :: uintptr(281) +SYS_userfaultfd :: uintptr(282) +SYS_membarrier :: uintptr(283) +SYS_mlock2 :: uintptr(284) +SYS_copy_file_range :: uintptr(285) +SYS_preadv2 :: uintptr(286) +SYS_pwritev2 :: uintptr(287) +SYS_pkey_mprotect :: uintptr(288) +SYS_pkey_alloc :: uintptr(289) +SYS_pkey_free :: uintptr(290) +SYS_statx :: uintptr(291) +SYS_io_pgetevents :: uintptr(292) +SYS_rseq :: uintptr(293) +SYS_kexec_file_load :: uintptr(294) +SYS_clock_gettime64 :: uintptr(403) +SYS_clock_settime64 :: uintptr(404) +SYS_clock_adjtime64 :: uintptr(405) +SYS_clock_getres_time64 :: uintptr(406) +SYS_clock_nanosleep_time64 :: uintptr(407) +SYS_timer_gettime64 :: uintptr(408) +SYS_timer_settime64 :: uintptr(409) +SYS_timerfd_gettime64 :: uintptr(410) +SYS_timerfd_settime64 :: uintptr(411) +SYS_utimensat_time64 :: uintptr(412) +SYS_pselect6_time64 :: uintptr(413) +SYS_ppoll_time64 :: uintptr(414) +SYS_io_pgetevents_time64 :: uintptr(416) +SYS_recvmmsg_time64 :: uintptr(417) +SYS_mq_timedsend_time64 :: uintptr(418) +SYS_mq_timedreceive_time64 :: uintptr(419) +SYS_semtimedop_time64 :: uintptr(420) +SYS_rt_sigtimedwait_time64 :: uintptr(421) +SYS_futex_time64 :: uintptr(422) +SYS_sched_rr_get_interval_time64 :: uintptr(423) +SYS_pidfd_send_signal :: uintptr(424) +SYS_io_uring_setup :: uintptr(425) +SYS_io_uring_enter :: uintptr(426) +SYS_io_uring_register :: uintptr(427) +SYS_open_tree :: uintptr(428) +SYS_move_mount :: uintptr(429) +SYS_fsopen :: uintptr(430) +SYS_fsconfig :: uintptr(431) +SYS_fsmount :: uintptr(432) +SYS_fspick :: uintptr(433) +SYS_pidfd_open :: uintptr(434) +SYS_clone3 :: uintptr(435) +SYS_close_range :: uintptr(436) +SYS_openat2 :: uintptr(437) +SYS_pidfd_getfd :: uintptr(438) +SYS_faccessat2 :: uintptr(439) +SYS_process_madvise :: uintptr(440) +SYS_epoll_pwait2 :: uintptr(441) +SYS_mount_setattr :: uintptr(442) +SYS_quotactl_fd :: uintptr(443) +SYS_landlock_create_ruleset :: uintptr(444) +SYS_landlock_add_rule :: uintptr(445) +SYS_landlock_restrict_self :: uintptr(446) +SYS_memfd_secret :: uintptr(447) +SYS_process_mrelease :: uintptr(448) +SYS_futex_waitv :: uintptr(449) +SYS_set_mempolicy_home_node :: uintptr(450) +SYS_cachestat :: uintptr(451) +SYS_fchmodat2 :: uintptr(452) diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin index 288edf879..c78a5b576 100644 --- a/core/sys/linux/types.odin +++ b/core/sys/linux/types.odin @@ -120,6 +120,25 @@ when ODIN_ARCH == .amd64 { _: [3]uint, } } else when ODIN_ARCH == .arm64 { + _Arch_Stat :: struct { + dev: Dev, + ino: Inode, + mode: Mode, + nlink: u32, + uid: Uid, + gid: Gid, + rdev: Dev, + _: u64, + size: int, + blksize: i32, + _: i32, + blocks: int, + atime: Time_Spec, + mtime: Time_Spec, + ctime: Time_Spec, + _: [2]u32, + } +} else when ODIN_ARCH == .riscv64 { _Arch_Stat :: struct { dev: Dev, ino: Inode, @@ -927,7 +946,7 @@ when ODIN_ARCH == .i386 { nsems: uint, _: [2]uint, } -} else when ODIN_ARCH == .arm64 { +} else when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { _Arch_Semid_DS :: struct { perm: IPC_Perm, otime: int, @@ -1167,6 +1186,33 @@ when ODIN_ARCH == .arm32 { xmm_space: [32]uint, padding: [56]uint, } +} else when ODIN_ARCH == .riscv64 { + _Arch_User_Regs :: struct { + pc, ra, sp, gp, tp, + t0, t1, t2, + s0, s1, + a0, a1, a2, a3, a4, a5, a6, a7, + s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, + t3, t4, t5, t6: uint, + } + _Arch_User_FP_Regs :: struct #raw_union { + f_ext: struct { + f: [32]u32, + fcsr: u32, + }, + d_ext: struct { + f: [32]u64, + fcsr: u32, + }, + q_ext: struct { + using _: struct #align(16) { + f: [64]u64, + }, + fcsr: u32, + reserved: [3]u32, + }, + } + _Arch_User_FPX_Regs :: struct {} } /* diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 038c16276..89ad2661f 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1514,6 +1514,338 @@ when ODIN_ARCH == .amd64 { SYS_landlock_create_ruleset : uintptr : 444 SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 +} else when ODIN_ARCH == .riscv64 { + SYS_io_setup :: uintptr(0) + SYS_io_destroy :: uintptr(1) + SYS_io_submit :: uintptr(2) + SYS_io_cancel :: uintptr(3) + SYS_io_getevents :: uintptr(4) + SYS_setxattr :: uintptr(5) + SYS_lsetxattr :: uintptr(6) + SYS_fsetxattr :: uintptr(7) + SYS_getxattr :: uintptr(8) + SYS_lgetxattr :: uintptr(9) + SYS_fgetxattr :: uintptr(10) + SYS_listxattr :: uintptr(11) + SYS_llistxattr :: uintptr(12) + SYS_flistxattr :: uintptr(13) + SYS_removexattr :: uintptr(14) + SYS_lremovexattr :: uintptr(15) + SYS_fremovexattr :: uintptr(16) + SYS_getcwd :: uintptr(17) + SYS_lookup_dcookie :: uintptr(18) + SYS_eventfd2 :: uintptr(19) + SYS_epoll_create1 :: uintptr(20) + SYS_epoll_ctl :: uintptr(21) + SYS_epoll_pwait :: uintptr(22) + SYS_dup :: uintptr(23) + SYS_dup3 :: uintptr(24) + SYS_fcntl :: uintptr(25) + SYS_inotify_init1 :: uintptr(26) + SYS_inotify_add_watch :: uintptr(27) + SYS_inotify_rm_watch :: uintptr(28) + SYS_ioctl :: uintptr(29) + SYS_ioprio_set :: uintptr(30) + SYS_ioprio_get :: uintptr(31) + SYS_flock :: uintptr(32) + SYS_mknodat :: uintptr(33) + SYS_mkdirat :: uintptr(34) + SYS_unlinkat :: uintptr(35) + SYS_symlinkat :: uintptr(36) + SYS_linkat :: uintptr(37) + SYS_renameat :: uintptr(38) + SYS_umount2 :: uintptr(39) + SYS_mount :: uintptr(40) + SYS_pivot_root :: uintptr(41) + SYS_nfsservctl :: uintptr(42) + SYS_statfs :: uintptr(43) + SYS_fstatfs :: uintptr(44) + SYS_truncate :: uintptr(45) + SYS_ftruncate :: uintptr(46) + SYS_fallocate :: uintptr(47) + SYS_faccessat :: uintptr(48) + SYS_chdir :: uintptr(49) + SYS_fchdir :: uintptr(50) + SYS_chroot :: uintptr(51) + SYS_fchmod :: uintptr(52) + SYS_fchmodat :: uintptr(53) + SYS_fchownat :: uintptr(54) + SYS_fchown :: uintptr(55) + SYS_openat :: uintptr(56) + SYS_close :: uintptr(57) + SYS_vhangup :: uintptr(58) + SYS_pipe2 :: uintptr(59) + SYS_quotactl :: uintptr(60) + SYS_getdents64 :: uintptr(61) + SYS_lseek :: uintptr(62) + SYS_read :: uintptr(63) + SYS_write :: uintptr(64) + SYS_readv :: uintptr(65) + SYS_writev :: uintptr(66) + SYS_pread64 :: uintptr(67) + SYS_pwrite64 :: uintptr(68) + SYS_preadv :: uintptr(69) + SYS_pwritev :: uintptr(70) + SYS_sendfile :: uintptr(71) + SYS_pselect6 :: uintptr(72) + SYS_ppoll :: uintptr(73) + SYS_signalfd4 :: uintptr(74) + SYS_vmsplice :: uintptr(75) + SYS_splice :: uintptr(76) + SYS_tee :: uintptr(77) + SYS_readlinkat :: uintptr(78) + SYS_fstatat :: uintptr(79) + SYS_fstat :: uintptr(80) + SYS_sync :: uintptr(81) + SYS_fsync :: uintptr(82) + SYS_fdatasync :: uintptr(83) + SYS_sync_file_range2 :: uintptr(84) + SYS_sync_file_range :: uintptr(84) + SYS_timerfd_create :: uintptr(85) + SYS_timerfd_settime :: uintptr(86) + SYS_timerfd_gettime :: uintptr(87) + SYS_utimensat :: uintptr(88) + SYS_acct :: uintptr(89) + SYS_capget :: uintptr(90) + SYS_capset :: uintptr(91) + SYS_personality :: uintptr(92) + SYS_exit :: uintptr(93) + SYS_exit_group :: uintptr(94) + SYS_waitid :: uintptr(95) + SYS_set_tid_address :: uintptr(96) + SYS_unshare :: uintptr(97) + SYS_futex :: uintptr(98) + SYS_set_robust_list :: uintptr(99) + SYS_get_robust_list :: uintptr(100) + SYS_nanosleep :: uintptr(101) + SYS_getitimer :: uintptr(102) + SYS_setitimer :: uintptr(103) + SYS_kexec_load :: uintptr(104) + SYS_init_module :: uintptr(105) + SYS_delete_module :: uintptr(106) + SYS_timer_create :: uintptr(107) + SYS_timer_gettime :: uintptr(108) + SYS_timer_getoverrun :: uintptr(109) + SYS_timer_settime :: uintptr(110) + SYS_timer_delete :: uintptr(111) + SYS_clock_settime :: uintptr(112) + SYS_clock_gettime :: uintptr(113) + SYS_clock_getres :: uintptr(114) + SYS_clock_nanosleep :: uintptr(115) + SYS_syslog :: uintptr(116) + SYS_ptrace :: uintptr(117) + SYS_sched_setparam :: uintptr(118) + SYS_sched_setscheduler :: uintptr(119) + SYS_sched_getscheduler :: uintptr(120) + SYS_sched_getparam :: uintptr(121) + SYS_sched_setaffinity :: uintptr(122) + SYS_sched_getaffinity :: uintptr(123) + SYS_sched_yield :: uintptr(124) + SYS_sched_get_priority_max :: uintptr(125) + SYS_sched_get_priority_min :: uintptr(126) + SYS_sched_rr_get_interval :: uintptr(127) + SYS_restart_syscall :: uintptr(128) + SYS_kill :: uintptr(129) + SYS_tkill :: uintptr(130) + SYS_tgkill :: uintptr(131) + SYS_sigaltstack :: uintptr(132) + SYS_rt_sigsuspend :: uintptr(133) + SYS_rt_sigaction :: uintptr(134) + SYS_rt_sigprocmask :: uintptr(135) + SYS_rt_sigpending :: uintptr(136) + SYS_rt_sigtimedwait :: uintptr(137) + SYS_rt_sigqueueinfo :: uintptr(138) + SYS_rt_sigreturn :: uintptr(139) + SYS_setpriority :: uintptr(140) + SYS_getpriority :: uintptr(141) + SYS_reboot :: uintptr(142) + SYS_setregid :: uintptr(143) + SYS_setgid :: uintptr(144) + SYS_setreuid :: uintptr(145) + SYS_setuid :: uintptr(146) + SYS_setresuid :: uintptr(147) + SYS_getresuid :: uintptr(148) + SYS_setresgid :: uintptr(149) + SYS_getresgid :: uintptr(150) + SYS_setfsuid :: uintptr(151) + SYS_setfsgid :: uintptr(152) + SYS_times :: uintptr(153) + SYS_setpgid :: uintptr(154) + SYS_getpgid :: uintptr(155) + SYS_getsid :: uintptr(156) + SYS_setsid :: uintptr(157) + SYS_getgroups :: uintptr(158) + SYS_setgroups :: uintptr(159) + SYS_uname :: uintptr(160) + SYS_sethostname :: uintptr(161) + SYS_setdomainname :: uintptr(162) + SYS_getrlimit :: uintptr(163) + SYS_setrlimit :: uintptr(164) + SYS_getrusage :: uintptr(165) + SYS_umask :: uintptr(166) + SYS_prctl :: uintptr(167) + SYS_getcpu :: uintptr(168) + SYS_gettimeofday :: uintptr(169) + SYS_settimeofday :: uintptr(170) + SYS_adjtimex :: uintptr(171) + SYS_getpid :: uintptr(172) + SYS_getppid :: uintptr(173) + SYS_getuid :: uintptr(174) + SYS_geteuid :: uintptr(175) + SYS_getgid :: uintptr(176) + SYS_getegid :: uintptr(177) + SYS_gettid :: uintptr(178) + SYS_sysinfo :: uintptr(179) + SYS_mq_open :: uintptr(180) + SYS_mq_unlink :: uintptr(181) + SYS_mq_timedsend :: uintptr(182) + SYS_mq_timedreceive :: uintptr(183) + SYS_mq_notify :: uintptr(184) + SYS_mq_getsetattr :: uintptr(185) + SYS_msgget :: uintptr(186) + SYS_msgctl :: uintptr(187) + SYS_msgrcv :: uintptr(188) + SYS_msgsnd :: uintptr(189) + SYS_semget :: uintptr(190) + SYS_semctl :: uintptr(191) + SYS_semtimedop :: uintptr(192) + SYS_semop :: uintptr(193) + SYS_shmget :: uintptr(194) + SYS_shmctl :: uintptr(195) + SYS_shmat :: uintptr(196) + SYS_shmdt :: uintptr(197) + SYS_socket :: uintptr(198) + SYS_socketpair :: uintptr(199) + SYS_bind :: uintptr(200) + SYS_listen :: uintptr(201) + SYS_accept :: uintptr(202) + SYS_connect :: uintptr(203) + SYS_getsockname :: uintptr(204) + SYS_getpeername :: uintptr(205) + SYS_sendto :: uintptr(206) + SYS_recvfrom :: uintptr(207) + SYS_setsockopt :: uintptr(208) + SYS_getsockopt :: uintptr(209) + SYS_shutdown :: uintptr(210) + SYS_sendmsg :: uintptr(211) + SYS_recvmsg :: uintptr(212) + SYS_readahead :: uintptr(213) + SYS_brk :: uintptr(214) + SYS_munmap :: uintptr(215) + SYS_mremap :: uintptr(216) + SYS_add_key :: uintptr(217) + SYS_request_key :: uintptr(218) + SYS_keyctl :: uintptr(219) + SYS_clone :: uintptr(220) + SYS_execve :: uintptr(221) + SYS_mmap :: uintptr(222) + SYS_fadvise64 :: uintptr(223) + SYS_swapon :: uintptr(224) + SYS_swapoff :: uintptr(225) + SYS_mprotect :: uintptr(226) + SYS_msync :: uintptr(227) + SYS_mlock :: uintptr(228) + SYS_munlock :: uintptr(229) + SYS_mlockall :: uintptr(230) + SYS_munlockall :: uintptr(231) + SYS_mincore :: uintptr(232) + SYS_madvise :: uintptr(233) + SYS_remap_file_pages :: uintptr(234) + SYS_mbind :: uintptr(235) + SYS_get_mempolicy :: uintptr(236) + SYS_set_mempolicy :: uintptr(237) + SYS_migrate_pages :: uintptr(238) + SYS_move_pages :: uintptr(239) + SYS_rt_tgsigqueueinfo :: uintptr(240) + SYS_perf_event_open :: uintptr(241) + SYS_accept4 :: uintptr(242) + SYS_recvmmsg :: uintptr(243) + SYS_wait4 :: uintptr(260) + SYS_prlimit64 :: uintptr(261) + SYS_fanotify_init :: uintptr(262) + SYS_fanotify_mark :: uintptr(263) + SYS_name_to_handle_at :: uintptr(264) + SYS_open_by_handle_at :: uintptr(265) + SYS_clock_adjtime :: uintptr(266) + SYS_syncfs :: uintptr(267) + SYS_setns :: uintptr(268) + SYS_sendmmsg :: uintptr(269) + SYS_process_vm_readv :: uintptr(270) + SYS_process_vm_writev :: uintptr(271) + SYS_kcmp :: uintptr(272) + SYS_finit_module :: uintptr(273) + SYS_sched_setattr :: uintptr(274) + SYS_sched_getattr :: uintptr(275) + SYS_renameat2 :: uintptr(276) + SYS_seccomp :: uintptr(277) + SYS_getrandom :: uintptr(278) + SYS_memfd_create :: uintptr(279) + SYS_bpf :: uintptr(280) + SYS_execveat :: uintptr(281) + SYS_userfaultfd :: uintptr(282) + SYS_membarrier :: uintptr(283) + SYS_mlock2 :: uintptr(284) + SYS_copy_file_range :: uintptr(285) + SYS_preadv2 :: uintptr(286) + SYS_pwritev2 :: uintptr(287) + SYS_pkey_mprotect :: uintptr(288) + SYS_pkey_alloc :: uintptr(289) + SYS_pkey_free :: uintptr(290) + SYS_statx :: uintptr(291) + SYS_io_pgetevents :: uintptr(292) + SYS_rseq :: uintptr(293) + SYS_kexec_file_load :: uintptr(294) + SYS_clock_gettime64 :: uintptr(403) + SYS_clock_settime64 :: uintptr(404) + SYS_clock_adjtime64 :: uintptr(405) + SYS_clock_getres_time64 :: uintptr(406) + SYS_clock_nanosleep_time64 :: uintptr(407) + SYS_timer_gettime64 :: uintptr(408) + SYS_timer_settime64 :: uintptr(409) + SYS_timerfd_gettime64 :: uintptr(410) + SYS_timerfd_settime64 :: uintptr(411) + SYS_utimensat_time64 :: uintptr(412) + SYS_pselect6_time64 :: uintptr(413) + SYS_ppoll_time64 :: uintptr(414) + SYS_io_pgetevents_time64 :: uintptr(416) + SYS_recvmmsg_time64 :: uintptr(417) + SYS_mq_timedsend_time64 :: uintptr(418) + SYS_mq_timedreceive_time64 :: uintptr(419) + SYS_semtimedop_time64 :: uintptr(420) + SYS_rt_sigtimedwait_time64 :: uintptr(421) + SYS_futex_time64 :: uintptr(422) + SYS_sched_rr_get_interval_time64 :: uintptr(423) + SYS_pidfd_send_signal :: uintptr(424) + SYS_io_uring_setup :: uintptr(425) + SYS_io_uring_enter :: uintptr(426) + SYS_io_uring_register :: uintptr(427) + SYS_open_tree :: uintptr(428) + SYS_move_mount :: uintptr(429) + SYS_fsopen :: uintptr(430) + SYS_fsconfig :: uintptr(431) + SYS_fsmount :: uintptr(432) + SYS_fspick :: uintptr(433) + SYS_pidfd_open :: uintptr(434) + SYS_clone3 :: uintptr(435) + SYS_close_range :: uintptr(436) + SYS_openat2 :: uintptr(437) + SYS_pidfd_getfd :: uintptr(438) + SYS_faccessat2 :: uintptr(439) + SYS_process_madvise :: uintptr(440) + SYS_epoll_pwait2 :: uintptr(441) + SYS_mount_setattr :: uintptr(442) + SYS_quotactl_fd :: uintptr(443) + SYS_landlock_create_ruleset :: uintptr(444) + SYS_landlock_add_rule :: uintptr(445) + SYS_landlock_restrict_self :: uintptr(446) + SYS_memfd_secret :: uintptr(447) + SYS_process_mrelease :: uintptr(448) + SYS_futex_waitv :: uintptr(449) + SYS_set_mempolicy_home_node :: uintptr(450) + SYS_cachestat :: uintptr(451) + SYS_fchmodat2 :: uintptr(452) + + SIGCHLD :: 17 } else { #panic("Unsupported architecture") } @@ -1742,7 +2074,7 @@ sys_getrandom :: proc "contextless" (buf: [^]byte, buflen: uint, flags: int) -> } sys_open :: proc "contextless" (path: cstring, flags: int, mode: uint = 0o000) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } else { // NOTE: arm64 does not have open return int(intrinsics.syscall(SYS_openat, AT_FDCWD, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) @@ -1762,7 +2094,7 @@ sys_read :: proc "contextless" (fd: int, buf: rawptr, size: uint) -> int { } sys_pread :: proc "contextless" (fd: int, buf: rawptr, size: uint, offset: i64) -> int { - when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { return int(intrinsics.syscall(SYS_pread64, uintptr(fd), uintptr(buf), uintptr(size), uintptr(offset))) } else { low := uintptr(offset & 0xFFFFFFFF) @@ -1776,7 +2108,7 @@ sys_write :: proc "contextless" (fd: int, buf: rawptr, size: uint) -> int { } sys_pwrite :: proc "contextless" (fd: int, buf: rawptr, size: uint, offset: i64) -> int { - when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { return int(intrinsics.syscall(SYS_pwrite64, uintptr(fd), uintptr(buf), uintptr(size), uintptr(offset))) } else { low := uintptr(offset & 0xFFFFFFFF) @@ -1786,7 +2118,7 @@ sys_pwrite :: proc "contextless" (fd: int, buf: rawptr, size: uint, offset: i64) } sys_lseek :: proc "contextless" (fd: int, offset: i64, whence: int) -> i64 { - when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { return i64(intrinsics.syscall(SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence))) } else { low := uintptr(offset & 0xFFFFFFFF) @@ -1800,7 +2132,7 @@ sys_lseek :: proc "contextless" (fd: int, offset: i64, whence: int) -> i64 { sys_stat :: proc "contextless" (path: cstring, stat: rawptr) -> int { when ODIN_ARCH == .amd64 { return int(intrinsics.syscall(SYS_stat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != .arm64 { + } else when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_stat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have stat return int(intrinsics.syscall(SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), 0)) @@ -1808,7 +2140,7 @@ sys_stat :: proc "contextless" (path: cstring, stat: rawptr) -> int { } sys_fstat :: proc "contextless" (fd: int, stat: rawptr) -> int { - when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { return int(intrinsics.syscall(SYS_fstat, uintptr(fd), uintptr(stat))) } else { return int(intrinsics.syscall(SYS_fstat64, uintptr(fd), uintptr(stat))) @@ -1818,7 +2150,7 @@ sys_fstat :: proc "contextless" (fd: int, stat: rawptr) -> int { sys_lstat :: proc "contextless" (path: cstring, stat: rawptr) -> int { when ODIN_ARCH == .amd64 { return int(intrinsics.syscall(SYS_lstat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != .arm64 { + } else when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_lstat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have any lstat return int(intrinsics.syscall(SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) @@ -1826,7 +2158,7 @@ sys_lstat :: proc "contextless" (path: cstring, stat: rawptr) -> int { } sys_readlink :: proc "contextless" (path: cstring, buf: rawptr, bufsiz: uint) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } else { // NOTE: arm64 does not have readlink return int(intrinsics.syscall(SYS_readlinkat, AT_FDCWD, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) @@ -1834,7 +2166,7 @@ sys_readlink :: proc "contextless" (path: cstring, buf: rawptr, bufsiz: uint) -> } sys_symlink :: proc "contextless" (old_name: cstring, new_name: cstring) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_symlink, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) } else { // NOTE: arm64 does not have symlink return int(intrinsics.syscall(SYS_symlinkat, uintptr(rawptr(old_name)), AT_FDCWD, uintptr(rawptr(new_name)))) @@ -1842,7 +2174,7 @@ sys_symlink :: proc "contextless" (old_name: cstring, new_name: cstring) -> int } sys_access :: proc "contextless" (path: cstring, mask: int) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_access, uintptr(rawptr(path)), uintptr(mask))) } else { // NOTE: arm64 does not have access return int(intrinsics.syscall(SYS_faccessat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mask))) @@ -1862,7 +2194,7 @@ sys_fchdir :: proc "contextless" (fd: int) -> int { } sys_chmod :: proc "contextless" (path: cstring, mode: uint) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_chmod, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have chmod return int(intrinsics.syscall(SYS_fchmodat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode))) @@ -1874,7 +2206,7 @@ sys_fchmod :: proc "contextless" (fd: int, mode: uint) -> int { } sys_chown :: proc "contextless" (path: cstring, user: int, group: int) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH !=. riscv64 { return int(intrinsics.syscall(SYS_chown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) } else { // NOTE: arm64 does not have chown return int(intrinsics.syscall(SYS_fchownat, AT_FDCWD, uintptr(rawptr(path)), uintptr(user), uintptr(group), 0)) @@ -1886,7 +2218,7 @@ sys_fchown :: proc "contextless" (fd: int, user: int, group: int) -> int { } sys_lchown :: proc "contextless" (path: cstring, user: int, group: int) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_lchown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) } else { // NOTE: arm64 does not have lchown return int(intrinsics.syscall(SYS_fchownat, AT_FDCWD, uintptr(rawptr(path)), uintptr(user), uintptr(group), AT_SYMLINK_NOFOLLOW)) @@ -1894,7 +2226,7 @@ sys_lchown :: proc "contextless" (path: cstring, user: int, group: int) -> int { } sys_rename :: proc "contextless" (old, new: cstring) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new)))) } else { // NOTE: arm64 does not have rename return int(intrinsics.syscall(SYS_renameat, AT_FDCWD, uintptr(rawptr(old)), uintptr(rawptr(new)))) @@ -1902,7 +2234,7 @@ sys_rename :: proc "contextless" (old, new: cstring) -> int { } sys_link :: proc "contextless" (old_name: cstring, new_name: cstring) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_link, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) } else { // NOTE: arm64 does not have link return int(intrinsics.syscall(SYS_linkat, AT_FDCWD, uintptr(rawptr(old_name)), AT_FDCWD, uintptr(rawptr(new_name)), AT_SYMLINK_FOLLOW)) @@ -1910,7 +2242,7 @@ sys_link :: proc "contextless" (old_name: cstring, new_name: cstring) -> int { } sys_unlink :: proc "contextless" (path: cstring) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_unlink, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have unlink return int(intrinsics.syscall(SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), 0)) @@ -1922,7 +2254,7 @@ sys_unlinkat :: proc "contextless" (dfd: int, path: cstring, flag: int = 0) -> i } sys_rmdir :: proc "contextless" (path: cstring) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_rmdir, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have rmdir return int(intrinsics.syscall(SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), AT_REMOVEDIR)) @@ -1930,7 +2262,7 @@ sys_rmdir :: proc "contextless" (path: cstring) -> int { } sys_mkdir :: proc "contextless" (path: cstring, mode: uint) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have mkdir return int(intrinsics.syscall(SYS_mkdirat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode))) @@ -1942,7 +2274,7 @@ sys_mkdirat :: proc "contextless" (dfd: int, path: cstring, mode: uint) -> int { } sys_mknod :: proc "contextless" (path: cstring, mode: uint, dev: int) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_mknod, uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) } else { // NOTE: arm64 does not have mknod return int(intrinsics.syscall(SYS_mknodat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) @@ -1954,7 +2286,7 @@ sys_mknodat :: proc "contextless" (dfd: int, path: cstring, mode: uint, dev: int } sys_truncate :: proc "contextless" (path: cstring, length: i64) -> int { - when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { return int(intrinsics.syscall(SYS_truncate, uintptr(rawptr(path)), uintptr(length))) } else { low := uintptr(length & 0xFFFFFFFF) @@ -1964,7 +2296,7 @@ sys_truncate :: proc "contextless" (path: cstring, length: i64) -> int { } sys_ftruncate :: proc "contextless" (fd: int, length: i64) -> int { - when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { return int(intrinsics.syscall(SYS_ftruncate, uintptr(fd), uintptr(length))) } else { low := uintptr(length & 0xFFFFFFFF) @@ -1982,7 +2314,7 @@ sys_getdents64 :: proc "contextless" (fd: int, dirent: rawptr, count: int) -> in } sys_fork :: proc "contextless" () -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_fork)) } else { return int(intrinsics.syscall(SYS_clone, SIGCHLD)) @@ -1992,7 +2324,7 @@ sys_pipe2 :: proc "contextless" (fds: rawptr, flags: int) -> int { return int(intrinsics.syscall(SYS_pipe2, uintptr(fds), uintptr(flags))) } sys_dup2 :: proc "contextless" (oldfd: int, newfd: int) -> int { - when ODIN_ARCH != .arm64 { + when ODIN_ARCH != .arm64 && ODIN_ARCH != .riscv64 { return int(intrinsics.syscall(SYS_dup2, uintptr(oldfd), uintptr(newfd))) } else { return int(intrinsics.syscall(SYS_dup3, uintptr(oldfd), uintptr(newfd), 0)) @@ -2076,7 +2408,7 @@ sys_fcntl :: proc "contextless" (fd: int, cmd: int, arg: int) -> int { sys_poll :: proc "contextless" (fds: rawptr, nfds: uint, timeout: int) -> int { // NOTE: specialcased here because `arm64` does not have `poll` - when ODIN_ARCH == .arm64 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { seconds := i64(timeout / 1_000) nanoseconds := i64((timeout % 1000) * 1_000_000) timeout_spec := timespec{seconds, nanoseconds} diff --git a/misc/featuregen/README.md b/misc/featuregen/README.md index 22a798cca..82d95a2b6 100644 --- a/misc/featuregen/README.md +++ b/misc/featuregen/README.md @@ -5,7 +5,7 @@ for features regarding microarchitecture and target features of the compiler. It is not pretty! But LLVM has no way to query this information with their C API. -It generates these globals (intended for `src/build_settings.cpp`: +It generates these globals (intended for `src/build_settings_microarch.cpp`: - `target_microarch_list`: an array of strings indexed by the architecture, each string is a comma-seperated list of microarchitectures available on that architecture - `target_features_list`: an array of strings indexed by the architecture, each string is a comma-seperated list of target features available on that architecture @@ -23,6 +23,6 @@ does not impact much at all, the only thing it will do is make LLVM print a mess ## Usage 1. Make sure the table of architectures at the top of the python script is up-to-date (the triple can be any valid triple for the architecture) -1. `./build.sh` +1. `./build_featuregen.sh` 1. `python3 featuregen.py` 1. Copy the output into `src/build_settings.cpp` diff --git a/misc/featuregen/build_featuregen.sh b/misc/featuregen/build_featuregen.sh new file mode 100755 index 000000000..d68f29925 --- /dev/null +++ b/misc/featuregen/build_featuregen.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +set -ex + +$(llvm-config --bindir)/clang++ $(llvm-config --cxxflags --ldflags --libs) featuregen.cpp -o featuregen diff --git a/misc/featuregen/featuregen.py b/misc/featuregen/featuregen.py index da4cc68f5..ecc47f70c 100644 --- a/misc/featuregen/featuregen.py +++ b/misc/featuregen/featuregen.py @@ -4,12 +4,13 @@ import os import sys archs = [ - ("amd64", "linux_amd64", "x86_64-pc-linux-gnu", [], []), - ("i386", "linux_i386", "i386-pc-linux-gnu", [], []), - ("arm32", "linux_arm32", "arm-linux-gnu", [], []), - ("arm64", "linux_arm64", "aarch64-linux-elf", [], []), - ("wasm32", "js_wasm32", "wasm32-js-js", [], []), - ("wasm64p32", "js_wasm64p32","wasm32-js-js", [], []), + ("amd64", "linux_amd64", "x86_64-pc-linux-gnu", [], []), + ("i386", "linux_i386", "i386-pc-linux-gnu", [], []), + ("arm32", "linux_arm32", "arm-linux-gnu", [], []), + ("arm64", "linux_arm64", "aarch64-linux-elf", [], []), + ("wasm32", "js_wasm32", "wasm32-js-js", [], []), + ("wasm64p32", "js_wasm64p32", "wasm32-js-js", [], []), + ("riscv64", "linux_riscv64", "riscv64-linux-gnu", [], []), ]; SEEKING_CPUS = 0 @@ -78,7 +79,8 @@ print("\t// TargetArch_Invalid:") print('\tstr_lit(""),') for arch, target, triple, cpus, features in archs: print(f"\t// TargetArch_{arch}:") - print(f'\tstr_lit("{','.join(cpus)}"),') + cpus_str = ','.join(cpus) + print(f'\tstr_lit("{cpus_str}"),') print("};") print("") @@ -89,7 +91,8 @@ print("\t// TargetArch_Invalid:") print('\tstr_lit(""),') for arch, target, triple, cpus, features in archs: print(f"\t// TargetArch_{arch}:") - print(f'\tstr_lit("{','.join(features)}"),') + features_str = ','.join(features) + print(f'\tstr_lit("{features_str}"),') print("};") print("") diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 82523d736..3d56f4202 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -39,6 +39,7 @@ enum TargetArchKind : u16 { TargetArch_arm64, TargetArch_wasm32, TargetArch_wasm64p32, + TargetArch_riscv64, TargetArch_COUNT, }; @@ -104,6 +105,7 @@ gb_global String target_arch_names[TargetArch_COUNT] = { str_lit("arm64"), str_lit("wasm32"), str_lit("wasm64p32"), + str_lit("riscv64"), }; #include "build_settings_microarch.cpp" @@ -555,13 +557,18 @@ gb_global TargetMetrics target_linux_arm64 = { 8, 8, 16, 32, str_lit("aarch64-linux-elf"), }; - gb_global TargetMetrics target_linux_arm32 = { TargetOs_linux, TargetArch_arm32, 4, 4, 8, 16, str_lit("arm-unknown-linux-gnueabihf"), }; +gb_global TargetMetrics target_linux_riscv64 = { + TargetOs_linux, + TargetArch_riscv64, + 8, 8, 16, 32, + str_lit("riscv64-linux-gnu"), +}; gb_global TargetMetrics target_darwin_amd64 = { TargetOs_darwin, @@ -716,6 +723,12 @@ gb_global TargetMetrics target_freestanding_arm32 = { 4, 4, 8, 16, str_lit("arm-unknown-unknown-gnueabihf"), }; +gb_global TargetMetrics target_freestanding_riscv64 = { + TargetOs_freestanding, + TargetArch_riscv64, + 8, 8, 16, 32, + str_lit("riscv64-unknown-gnu"), +}; struct NamedTargetMetrics { @@ -733,6 +746,7 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("linux_amd64"), &target_linux_amd64 }, { str_lit("linux_arm64"), &target_linux_arm64 }, { str_lit("linux_arm32"), &target_linux_arm32 }, + { str_lit("linux_riscv64"), &target_linux_riscv64 }, { str_lit("windows_i386"), &target_windows_i386 }, { str_lit("windows_amd64"), &target_windows_amd64 }, @@ -761,6 +775,8 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("freestanding_arm64"), &target_freestanding_arm64 }, { str_lit("freestanding_arm32"), &target_freestanding_arm32 }, + + { str_lit("freestanding_riscv64"), &target_freestanding_riscv64 }, }; gb_global NamedTargetMetrics *selected_target_metrics; @@ -1631,6 +1647,8 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta // Disallow on wasm bc->use_separate_modules = false; + } if(bc->metrics.arch == TargetArch_riscv64) { + bc->link_flags = str_lit("-target riscv64 "); } else { // NOTE: for targets other than darwin, we don't specify a `-target` link flag. // This is because we don't support cross-linking and clang is better at figuring diff --git a/src/build_settings_microarch.cpp b/src/build_settings_microarch.cpp index 02b507031..8f64d4026 100644 --- a/src/build_settings_microarch.cpp +++ b/src/build_settings_microarch.cpp @@ -3,17 +3,19 @@ gb_global String target_microarch_list[TargetArch_COUNT] = { // TargetArch_Invalid: str_lit(""), // TargetArch_amd64: - str_lit("alderlake,amdfam10,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,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,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,penryn,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,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4"), + str_lit("alderlake,amdfam10,arrowlake,arrowlake-s,arrowlake_s,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,clearwaterforest,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,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,gracemont,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,lunarlake,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,pantherlake,penryn,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,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4"), // TargetArch_i386: - str_lit("alderlake,amdfam10,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,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,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,penryn,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,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4"), + str_lit("alderlake,amdfam10,arrowlake,arrowlake-s,arrowlake_s,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,clearwaterforest,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,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,gracemont,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,lunarlake,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,pantherlake,penryn,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,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4"), // 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,iwmmxt,krait,kryo,mpcore,mpcorenovfp,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-m52,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,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,kryo,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,ampere1b,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a17,apple-a7,apple-a8,apple-a9,apple-latest,apple-m1,apple-m2,apple-m3,apple-s4,apple-s5,carmel,cortex-a34,cortex-a35,cortex-a510,cortex-a520,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a720,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78c,cortex-r82,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cortex-x4,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,generic,kryo,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-v1,neoverse-v2,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), // TargetArch_wasm32: str_lit("bleeding-edge,generic,mvp"), // TargetArch_wasm64p32: str_lit("bleeding-edge,generic,mvp"), + // TargetArch_riscv64: + str_lit("generic,generic-rv32,generic-rv64,rocket,rocket-rv32,rocket-rv64,sifive-7-series,sifive-e20,sifive-e21,sifive-e24,sifive-e31,sifive-e34,sifive-e76,sifive-p450,sifive-p670,sifive-s21,sifive-s51,sifive-s54,sifive-s76,sifive-u54,sifive-u74,sifive-x280,syntacore-scr1-base,syntacore-scr1-max,veyron-v1,xiangshan-nanhu"), }; // Generated with the featuregen script in `misc/featuregen` @@ -21,17 +23,19 @@ gb_global String target_features_list[TargetArch_COUNT] = { // TargetArch_Invalid: str_lit(""), // TargetArch_amd64: - str_lit("16bit-mode,32bit-mode,3dnow,3dnowa,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512er,avx512f,avx512fp16,avx512ifma,avx512pf,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branchfusion,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-gather,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prefetchwt1,prfchw,ptwrite,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves"), + str_lit("16bit-mode,32bit-mode,3dnow,3dnowa,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx10.1-256,avx10.1-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512er,avx512f,avx512fp16,avx512ifma,avx512pf,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branchfusion,ccmp,cf,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-gather,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,ndd,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,ppx,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prefetchwt1,prfchw,ptwrite,push2pop2,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves"), // TargetArch_i386: - str_lit("16bit-mode,32bit-mode,3dnow,3dnowa,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512er,avx512f,avx512fp16,avx512ifma,avx512pf,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branchfusion,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,ermsb,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-gather,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prefetchwt1,prfchw,ptwrite,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves"), + str_lit("16bit-mode,32bit-mode,3dnow,3dnowa,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx10.1-256,avx10.1-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512er,avx512f,avx512fp16,avx512ifma,avx512pf,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branchfusion,ccmp,cf,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-gather,fast-hops,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,ndd,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,ppx,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prefetchwt1,prfchw,ptwrite,push2pop2,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves"), // TargetArch_arm32: - str_lit("32bit,8msecext,a12,a15,a17,a32,a35,a5,a53,a55,a57,a7,a72,a73,a75,a76,a77,a78c,a8,a9,aapcs-frame-chain,aapcs-frame-chain-leaf,aclass,acquire-release,aes,armv4,armv4t,armv5t,armv5te,armv5tej,armv6,armv6-m,armv6j,armv6k,armv6kz,armv6s-m,armv6t2,armv7-a,armv7-m,armv7-r,armv7e-m,armv7k,armv7s,armv7ve,armv8-a,armv8-m.base,armv8-m.main,armv8-r,armv8.1-a,armv8.1-m.main,armv8.2-a,armv8.3-a,armv8.4-a,armv8.5-a,armv8.6-a,armv8.7-a,armv8.8-a,armv8.9-a,armv9-a,armv9.1-a,armv9.2-a,armv9.3-a,armv9.4-a,atomics-32,avoid-movs-shop,avoid-partial-cpsr,bf16,big-endian-instructions,cde,cdecp0,cdecp1,cdecp2,cdecp3,cdecp4,cdecp5,cdecp6,cdecp7,cheap-predicable-cpsr,clrbhb,cortex-a710,cortex-a78,cortex-x1,cortex-x1c,crc,crypto,d32,db,dfb,disable-postra-scheduler,dont-widen-vmovs,dotprod,dsp,execute-only,expand-fp-mlx,exynos,fix-cmse-cve-2021-35465,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpao,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hwdiv,hwdiv-arm,i8mm,iwmmxt,iwmmxt2,krait,kryo,lob,long-calls,loop-align,m3,m7,mclass,mp,muxed-units,mve,mve.fp,mve1beat,mve2beat,mve4beat,nacl-trap,neon,neon-fpmovs,neonfp,neoverse-v1,no-branch-predictor,no-bti-at-return-twice,no-movt,no-neg-immediates,noarm,nonpipelined-vfp,pacbti,perfmon,prefer-ishst,prefer-vmovsr,prof-unpr,r4,r5,r52,r7,ras,rclass,read-tp-tpidrprw,read-tp-tpidruro,read-tp-tpidrurw,reserve-r9,ret-addr-stack,sb,sha2,slow-fp-brcc,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,soft-float,splat-vfp-neon,strict-align,swift,thumb-mode,thumb2,trustzone,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.1m.main,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8m,v8m.main,v9.1a,v9.2a,v9.3a,v9.4a,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align,vmlx-forwarding,vmlx-hazards,wide-stride-vfp,xscale,zcz"), + str_lit("32bit,8msecext,a12,a15,a17,a32,a35,a5,a53,a55,a57,a7,a72,a73,a75,a76,a77,a78c,a8,a9,aapcs-frame-chain,aapcs-frame-chain-leaf,aclass,acquire-release,aes,armv4,armv4t,armv5t,armv5te,armv5tej,armv6,armv6-m,armv6j,armv6k,armv6kz,armv6s-m,armv6t2,armv7-a,armv7-m,armv7-r,armv7e-m,armv7k,armv7s,armv7ve,armv8-a,armv8-m.base,armv8-m.main,armv8-r,armv8.1-a,armv8.1-m.main,armv8.2-a,armv8.3-a,armv8.4-a,armv8.5-a,armv8.6-a,armv8.7-a,armv8.8-a,armv8.9-a,armv9-a,armv9.1-a,armv9.2-a,armv9.3-a,armv9.4-a,armv9.5-a,atomics-32,avoid-movs-shop,avoid-partial-cpsr,bf16,big-endian-instructions,cde,cdecp0,cdecp1,cdecp2,cdecp3,cdecp4,cdecp5,cdecp6,cdecp7,cheap-predicable-cpsr,clrbhb,cortex-a710,cortex-a78,cortex-x1,cortex-x1c,crc,crypto,d32,db,dfb,disable-postra-scheduler,dont-widen-vmovs,dotprod,dsp,execute-only,expand-fp-mlx,exynos,fix-cmse-cve-2021-35465,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpao,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hwdiv,hwdiv-arm,i8mm,iwmmxt,iwmmxt2,krait,kryo,lob,long-calls,loop-align,m3,m7,mclass,mp,muxed-units,mve,mve.fp,mve1beat,mve2beat,mve4beat,nacl-trap,neon,neon-fpmovs,neonfp,neoverse-v1,no-branch-predictor,no-bti-at-return-twice,no-movt,no-neg-immediates,noarm,nonpipelined-vfp,pacbti,perfmon,prefer-ishst,prefer-vmovsr,prof-unpr,r4,r5,r52,r7,ras,rclass,read-tp-tpidrprw,read-tp-tpidruro,read-tp-tpidrurw,reserve-r9,ret-addr-stack,sb,sha2,slow-fp-brcc,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,soft-float,splat-vfp-neon,strict-align,swift,thumb-mode,thumb2,trustzone,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.1m.main,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8m,v8m.main,v9.1a,v9.2a,v9.3a,v9.4a,v9.5a,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align,vmlx-forwarding,vmlx-hazards,wide-stride-vfp,xscale,zcz"), // TargetArch_arm64: - str_lit("CONTEXTIDREL2,a35,a510,a53,a55,a57,a64fx,a65,a710,a715,a72,a73,a75,a76,a77,a78,a78c,aes,aggressive-fma,all,alternate-sextload-cvt-f32-pattern,altnzcv,am,ampere1,ampere1a,amvs,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,ascend-store-address,b16b16,balance-fp-ops,bf16,brbe,bti,call-saved-x10,call-saved-x11,call-saved-x12,call-saved-x13,call-saved-x14,call-saved-x15,call-saved-x18,call-saved-x8,call-saved-x9,carmel,ccdp,ccidx,ccpp,chk,clrbhb,cmp-bcc-fusion,complxnum,cortex-r82,cortex-x1,cortex-x2,cortex-x3,crc,crypto,cssc,custom-cheap-as-move,d128,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,exynos-cheap-as-move,exynosm3,exynosm4,f32mm,f64mm,falkor,fgt,fix-cortex-a53-835769,flagm,fmv,force-32bit-jump-tables,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,gcs,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hbc,hcx,i8mm,ite,jsconv,kryo,lor,ls64,lse,lse128,lse2,lsl-fast,mec,mops,mpam,mte,neon,neoverse512tvb,neoversee1,neoversen1,neoversen2,neoversev1,neoversev2,nmi,no-bti-at-return-twice,no-neg-immediates,no-sve-fp-ld1r,no-zcz-fp,nv,outline-atomics,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,prfm-slc-target,rand,ras,rasv2,rcpc,rcpc-immo,rcpc3,rdm,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x18,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x3,reserve-x30,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x9,rme,saphira,sb,sel2,sha2,sha3,slow-misaligned-128store,slow-paired-128,slow-strqro-store,sm4,sme,sme-f16f16,sme-f64f64,sme-i16i64,sme2,sme2p1,spe,spe-eef,specres2,specrestrict,ssbs,strict-align,sve,sve2,sve2-aes,sve2-bitperm,sve2-sha3,sve2-sm4,sve2p1,tagged-globals,the,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tlb-rmi,tme,tpidr-el1,tpidr-el2,tpidr-el3,tpidrro-el0,tracev8.4,trbe,tsv110,uaops,use-experimental-zeroing-pseudos,use-postra-scheduler,use-reciprocal-square-root,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8a,v8r,v9.1a,v9.2a,v9.3a,v9.4a,v9a,vh,wfxt,xs,zcm,zcz,zcz-fp-workaround,zcz-gp"), + str_lit("CONTEXTIDREL2,a35,a510,a520,a53,a55,a57,a64fx,a65,a710,a715,a72,a720,a73,a75,a76,a77,a78,a78c,addr-lsl-fast,aes,aggressive-fma,all,alternate-sextload-cvt-f32-pattern,altnzcv,alu-lsl-fast,am,ampere1,ampere1a,ampere1b,amvs,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a17,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,ascend-store-address,b16b16,balance-fp-ops,bf16,brbe,bti,call-saved-x10,call-saved-x11,call-saved-x12,call-saved-x13,call-saved-x14,call-saved-x15,call-saved-x18,call-saved-x8,call-saved-x9,carmel,ccdp,ccidx,ccpp,chk,clrbhb,cmp-bcc-fusion,complxnum,cortex-r82,cortex-x1,cortex-x2,cortex-x3,cortex-x4,cpa,crc,crypto,cssc,d128,disable-latency-sched-heuristic,disable-ldp,disable-stp,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,exynos-cheap-as-move,exynosm3,exynosm4,f32mm,f64mm,falkor,faminmax,fgt,fix-cortex-a53-835769,flagm,fmv,force-32bit-jump-tables,fp-armv8,fp16fml,fp8,fp8dot2,fp8dot4,fp8fma,fpmr,fptoint,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,gcs,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hbc,hcx,i8mm,ite,jsconv,kryo,ldp-aligned-only,lor,ls64,lse,lse128,lse2,lut,mec,mops,mpam,mte,neon,neoverse512tvb,neoversee1,neoversen1,neoversen2,neoversev1,neoversev2,nmi,no-bti-at-return-twice,no-neg-immediates,no-sve-fp-ld1r,no-zcz-fp,nv,outline-atomics,pan,pan-rwv,pauth,pauth-lr,perfmon,predictable-select-expensive,predres,prfm-slc-target,rand,ras,rasv2,rcpc,rcpc-immo,rcpc3,rdm,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x18,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x3,reserve-x30,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x9,rme,saphira,sb,sel2,sha2,sha3,slow-misaligned-128store,slow-paired-128,slow-strqro-store,sm4,sme,sme-f16f16,sme-f64f64,sme-f8f16,sme-f8f32,sme-fa64,sme-i16i64,sme-lutv2,sme2,sme2p1,spe,spe-eef,specres2,specrestrict,ssbs,ssve-fp8dot2,ssve-fp8dot4,ssve-fp8fma,store-pair-suppress,stp-aligned-only,strict-align,sve,sve2,sve2-aes,sve2-bitperm,sve2-sha3,sve2-sm4,sve2p1,tagged-globals,the,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tlb-rmi,tlbiw,tme,tpidr-el1,tpidr-el2,tpidr-el3,tpidrro-el0,tracev8.4,trbe,tsv110,uaops,use-experimental-zeroing-pseudos,use-postra-scheduler,use-reciprocal-square-root,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8a,v8r,v9.1a,v9.2a,v9.3a,v9.4a,v9.5a,v9a,vh,wfxt,xs,zcm,zcz,zcz-fp-workaround,zcz-gp"), // TargetArch_wasm32: - str_lit("atomics,bulk-memory,exception-handling,extended-const,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call"), + str_lit("atomics,bulk-memory,exception-handling,extended-const,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call"), // TargetArch_wasm64p32: - str_lit("atomics,bulk-memory,exception-handling,extended-const,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call"), + str_lit("atomics,bulk-memory,exception-handling,extended-const,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call"), + // TargetArch_riscv64: + str_lit("32bit,64bit,a,auipc-addi-fusion,c,conditional-cmv-fusion,d,dlen-factor-2,e,experimental,experimental-zacas,experimental-zcmop,experimental-zfbfmin,experimental-zicfilp,experimental-zicfiss,experimental-zimop,experimental-ztso,experimental-zvfbfmin,experimental-zvfbfwma,f,fast-unaligned-access,forced-atomics,h,i,ld-add-fusion,lui-addi-fusion,m,no-default-unroll,no-optimized-zero-stride-load,no-rvc-hints,relax,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x16,reserve-x17,reserve-x18,reserve-x19,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x29,reserve-x3,reserve-x30,reserve-x31,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x8,reserve-x9,save-restore,seq-cst-trailing-fence,shifted-zextw-fusion,short-forward-branch-opt,sifive7,smaia,smepmp,ssaia,svinval,svnapot,svpbmt,tagged-globals,unaligned-scalar-mem,use-postra-scheduler,v,ventana-veyron,xcvalu,xcvbi,xcvbitmanip,xcvelw,xcvmac,xcvmem,xcvsimd,xsfvcp,xsfvfnrclipxfqf,xsfvfwmaccqqq,xsfvqmaccdod,xsfvqmaccqoq,xtheadba,xtheadbb,xtheadbs,xtheadcmo,xtheadcondmov,xtheadfmemidx,xtheadmac,xtheadmemidx,xtheadmempair,xtheadsync,xtheadvdot,xventanacondops,za128rs,za64rs,zawrs,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zca,zcb,zcd,zce,zcf,zcmp,zcmt,zdinx,zexth-fusion,zextw-fusion,zfa,zfh,zfhmin,zfinx,zhinx,zhinxmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zk,zkn,zknd,zkne,zknh,zkr,zks,zksed,zksh,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknha,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl1024b,zvl128b,zvl16384b,zvl2048b,zvl256b,zvl32768b,zvl32b,zvl4096b,zvl512b,zvl64b,zvl65536b,zvl8192b"), }; // Generated with the featuregen script in `misc/featuregen` @@ -39,17 +43,19 @@ gb_global int target_microarch_counts[TargetArch_COUNT] = { // TargetArch_Invalid: 0, // TargetArch_amd64: - 120, + 127, // TargetArch_i386: - 120, + 127, // TargetArch_arm32: - 90, + 91, // TargetArch_arm64: - 63, + 69, // TargetArch_wasm32: 3, // TargetArch_wasm64p32: 3, + // TargetArch_riscv64: + 26, }; // Generated with the featuregen script in `misc/featuregen` @@ -57,6 +63,9 @@ gb_global MicroarchFeatureList microarch_features_list[] = { // TargetArch_amd64: { str_lit("alderlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("amdfam10"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("arrowlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake-s"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake_s"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("athlon"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, { str_lit("athlon-4"), str_lit("3dnow,3dnowa,64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, { str_lit("athlon-fx"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, @@ -81,6 +90,7 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("c3-2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, { str_lit("cannonlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("cascadelake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("clearwaterforest"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("cooperlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("core-avx-i"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, { str_lit("core-avx2"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, @@ -103,6 +113,7 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("goldmont"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("goldmont-plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("goldmont_plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("gracemont"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("grandridge"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("graniterapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("graniterapids-d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, @@ -125,12 +136,14 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("knl"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, { str_lit("knm"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, { str_lit("lakemont"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper") }, + { str_lit("lunarlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("meteorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("mic_avx512"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, { str_lit("nehalem"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, { str_lit("nocona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, { str_lit("opteron"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, { str_lit("opteron-sse3"), str_lit("3dnow,3dnowa,64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pantherlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("penryn"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, { str_lit("pentium"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, { str_lit("pentium-m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, @@ -178,6 +191,9 @@ gb_global MicroarchFeatureList microarch_features_list[] = { // TargetArch_i386: { str_lit("alderlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("amdfam10"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("arrowlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake-s"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake_s"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("athlon"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,mmx,nopl,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, { str_lit("athlon-4"), str_lit("32bit-mode,3dnow,3dnowa,cmov,cx8,fxsr,mmx,nopl,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, { str_lit("athlon-fx"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, @@ -202,6 +218,7 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("c3-2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,vzeroupper,x87") }, { str_lit("cannonlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("cascadelake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("clearwaterforest"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("cooperlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("core-avx-i"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, { str_lit("core-avx2"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, @@ -224,6 +241,7 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("goldmont"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("goldmont-plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("goldmont_plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("gracemont"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivl-to-divb,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("grandridge"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,fast-movbe,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,mmx,movbe,movdir64b,movdiri,no-bypass-delay,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,use-glm-div-sqrt-costs,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("graniterapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("graniterapids-d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, @@ -246,12 +264,14 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("knl"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, { str_lit("knm"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, { str_lit("lakemont"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper") }, + { str_lit("lunarlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("meteorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("mic_avx512"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512er,avx512f,avx512pf,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prefetchwt1,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, { str_lit("nehalem"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, { str_lit("nocona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, { str_lit("opteron"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, { str_lit("opteron-sse3"), str_lit("32bit-mode,3dnow,3dnowa,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pantherlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, { str_lit("penryn"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, { str_lit("pentium"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, { str_lit("pentium-m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, @@ -325,16 +345,16 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("arm968e-s"), str_lit("armv5te,v4t,v5t,v5te") }, { str_lit("arm9e"), str_lit("armv5te,v4t,v5t,v5te") }, { str_lit("arm9tdmi"), str_lit("armv4t,v4t") }, - { str_lit("cortex-a12"), str_lit("a12,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, - { str_lit("cortex-a15"), str_lit("a15,aclass,armv7-a,avoid-partial-cpsr,d32,db,dont-widen-vmovs,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,muxed-units,neon,perfmon,ret-addr-stack,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align") }, - { str_lit("cortex-a17"), str_lit("a17,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a12"), str_lit("a12,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a15"), str_lit("a15,aclass,armv7-a,avoid-partial-cpsr,d32,db,dont-widen-vmovs,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,muxed-units,perfmon,ret-addr-stack,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align") }, + { str_lit("cortex-a17"), str_lit("a17,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, { str_lit("cortex-a32"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, { str_lit("cortex-a35"), str_lit("a35,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a5"), str_lit("a5,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-forwarding") }, + { str_lit("cortex-a5"), str_lit("a5,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,mp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-forwarding") }, { str_lit("cortex-a53"), str_lit("a53,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, { str_lit("cortex-a55"), str_lit("a55,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, { str_lit("cortex-a57"), str_lit("a57,aclass,acquire-release,aes,armv8-a,avoid-partial-cpsr,cheap-predicable-cpsr,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a7"), str_lit("a7,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a7"), str_lit("a7,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding,vmlx-hazards") }, { str_lit("cortex-a710"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, { str_lit("cortex-a72"), str_lit("a72,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, { str_lit("cortex-a73"), str_lit("a73,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, @@ -344,8 +364,8 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("cortex-a77"), str_lit("a77,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, { str_lit("cortex-a78"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, { str_lit("cortex-a78c"), str_lit("a78c,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, - { str_lit("cortex-a8"), str_lit("a8,aclass,armv7-a,d32,db,dsp,fp64,fpregs,fpregs64,neon,nonpipelined-vfp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vmlx-forwarding,vmlx-hazards") }, - { str_lit("cortex-a9"), str_lit("a9,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,expand-fp-mlx,fp16,fp64,fpregs,fpregs64,mp,muxed-units,neon,neon-fpmovs,perfmon,prefer-vmovsr,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vldn-align,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a8"), str_lit("a8,aclass,armv7-a,d32,db,dsp,fp64,fpregs,fpregs64,nonpipelined-vfp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a9"), str_lit("a9,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,expand-fp-mlx,fp16,fp64,fpregs,fpregs64,mp,muxed-units,neon-fpmovs,perfmon,prefer-vmovsr,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vldn-align,vmlx-forwarding,vmlx-hazards") }, { str_lit("cortex-m0"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, { str_lit("cortex-m0plus"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, { str_lit("cortex-m1"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, @@ -354,6 +374,7 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("cortex-m33"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, { str_lit("cortex-m35p"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, { str_lit("cortex-m4"), str_lit("armv7e-m,db,dsp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m52"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,mclass,mve,mve.fp,mve1beat,no-branch-predictor,noarm,pacbti,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, { str_lit("cortex-m55"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,mclass,mve,mve.fp,no-branch-predictor,noarm,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, { str_lit("cortex-m7"), str_lit("armv7e-m,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs64,hwdiv,m7,mclass,noarm,thumb-mode,thumb2,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, { str_lit("cortex-m85"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,mclass,mve,mve.fp,noarm,pacbti,ras,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, @@ -372,7 +393,7 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("exynos-m5"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, { str_lit("generic"), str_lit("") }, { str_lit("iwmmxt"), str_lit("armv5te,v4t,v5t,v5te") }, - { str_lit("krait"), str_lit("aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,krait,muxed-units,neon,perfmon,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vldn-align,vmlx-forwarding") }, + { str_lit("krait"), str_lit("aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,krait,muxed-units,perfmon,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vldn-align,vmlx-forwarding") }, { str_lit("kryo"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,kryo,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, { str_lit("mpcore"), str_lit("armv6k,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, { str_lit("mpcorenovfp"), str_lit("armv6k,v4t,v5t,v5te,v6,v6k") }, @@ -385,12 +406,13 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("strongarm110"), str_lit("armv4") }, { str_lit("strongarm1100"), str_lit("armv4") }, { str_lit("strongarm1110"), str_lit("armv4") }, - { str_lit("swift"), str_lit("aclass,armv7-a,avoid-movs-shop,avoid-partial-cpsr,d32,db,disable-postra-scheduler,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,prefer-ishst,prof-unpr,ret-addr-stack,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,swift,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-hazards,wide-stride-vfp") }, + { str_lit("swift"), str_lit("aclass,armv7-a,avoid-movs-shop,avoid-partial-cpsr,d32,db,disable-postra-scheduler,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neonfp,perfmon,prefer-ishst,prof-unpr,ret-addr-stack,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,swift,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-hazards,wide-stride-vfp") }, { str_lit("xscale"), str_lit("armv5te,v4t,v5t,v5te") }, // TargetArch_arm64: { str_lit("a64fx"), str_lit("CONTEXTIDREL2,a64fx,aggressive-fma,arith-bcc-fusion,ccpp,complxnum,crc,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rdm,sha2,store-pair-suppress,sve,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, { str_lit("ampere1"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fuse-address,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, { str_lit("ampere1a"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1a,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fuse-address,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("ampere1b"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1b,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,cssc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,hcx,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs") }, { str_lit("apple-a10"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a10,arith-bcc-fusion,arith-cbz-fusion,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,lor,neon,pan,perfmon,rdm,sha2,store-pair-suppress,v8a,vh,zcm,zcz,zcz-gp") }, { str_lit("apple-a11"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a11,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8a,vh,zcm,zcz,zcz-gp") }, { str_lit("apple-a12"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, @@ -398,18 +420,21 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("apple-a14"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, { str_lit("apple-a15"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, { str_lit("apple-a16"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a17"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a17,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, { str_lit("apple-a7"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, { str_lit("apple-a8"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, { str_lit("apple-a9"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, { str_lit("apple-latest"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, { str_lit("apple-m1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, { str_lit("apple-m2"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-m3"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, { str_lit("apple-s4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, { str_lit("apple-s5"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccidx,ccpp,complxnum,crc,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, { str_lit("carmel"), str_lit("CONTEXTIDREL2,aes,carmel,ccpp,crc,crypto,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,ras,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, { str_lit("cortex-a34"), str_lit("a35,aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, { str_lit("cortex-a35"), str_lit("a35,aes,crc,crypto,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, { str_lit("cortex-a510"), str_lit("CONTEXTIDREL2,a510,altnzcv,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a520"), str_lit("CONTEXTIDREL2,a520,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, { str_lit("cortex-a53"), str_lit("a53,aes,balance-fp-ops,crc,crypto,el2vmsa,el3,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,sha2,use-postra-scheduler,v8a") }, { str_lit("cortex-a55"), str_lit("CONTEXTIDREL2,a55,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, { str_lit("cortex-a57"), str_lit("a57,aes,balance-fp-ops,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,use-postra-scheduler,v8a") }, @@ -418,6 +443,7 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("cortex-a710"), str_lit("CONTEXTIDREL2,a710,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, { str_lit("cortex-a715"), str_lit("CONTEXTIDREL2,a715,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, { str_lit("cortex-a72"), str_lit("a72,aes,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,v8a") }, + { str_lit("cortex-a720"), str_lit("CONTEXTIDREL2,a720,addr-lsl-fast,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, { str_lit("cortex-a73"), str_lit("a73,aes,crc,crypto,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,predictable-select-expensive,sha2,v8a") }, { str_lit("cortex-a75"), str_lit("CONTEXTIDREL2,a75,aes,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, { str_lit("cortex-a76"), str_lit("CONTEXTIDREL2,a76,addr-lsl-fast,aes,alu-lsl-fast,ccpp,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, @@ -430,6 +456,7 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("cortex-x1c"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,crypto,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,lse2,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, { str_lit("cortex-x2"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-x2,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, { str_lit("cortex-x3"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x3,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-x4"), str_lit("CONTEXTIDREL2,addr-lsl-fast,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x4,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mec,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve2,sve2-bitperm,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,use-scalar-inc-vl,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, { str_lit("cyclone"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,apple-a7-sysreg,arith-bcc-fusion,arith-cbz-fusion,crypto,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, { str_lit("exynos-m3"), str_lit("addr-lsl-fast,aes,alu-lsl-fast,crc,crypto,el2vmsa,el3,exynos-cheap-as-move,exynosm3,force-32bit-jump-tables,fp-armv8,fuse-address,fuse-adrp-add,fuse-aes,fuse-csel,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a") }, { str_lit("exynos-m4"), str_lit("CONTEXTIDREL2,addr-lsl-fast,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,crypto,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") }, @@ -459,4 +486,31 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,mutable-globals,nontrapping-fptoint,sign-ext,simd128,tail-call") }, { str_lit("generic"), str_lit("mutable-globals,sign-ext") }, { str_lit("mvp"), str_lit("") }, -}; \ No newline at end of file + // TargetArch_riscv64: + { str_lit("generic"), str_lit("64bit") }, + { str_lit("generic-rv32"), str_lit("32bit") }, + { str_lit("generic-rv64"), str_lit("64bit") }, + { str_lit("rocket"), str_lit("") }, + { str_lit("rocket-rv32"), str_lit("32bit,zicsr,zifencei") }, + { str_lit("rocket-rv64"), str_lit("64bit,zicsr,zifencei") }, + { str_lit("sifive-7-series"), str_lit("no-default-unroll,short-forward-branch-opt,sifive7") }, + { str_lit("sifive-e20"), str_lit("32bit,c,m,zicsr,zifencei") }, + { str_lit("sifive-e21"), str_lit("32bit,a,c,m,zicsr,zifencei") }, + { str_lit("sifive-e24"), str_lit("32bit,a,c,f,m,zicsr,zifencei") }, + { str_lit("sifive-e31"), str_lit("32bit,a,c,m,zicsr,zifencei") }, + { str_lit("sifive-e34"), str_lit("32bit,a,c,f,m,zicsr,zifencei") }, + { str_lit("sifive-e76"), str_lit("32bit,a,c,f,m,no-default-unroll,short-forward-branch-opt,sifive7,zicsr,zifencei") }, + { str_lit("sifive-p450"), str_lit("64bit,a,auipc-addi-fusion,c,conditional-cmv-fusion,d,f,fast-unaligned-access,lui-addi-fusion,m,no-default-unroll,za64rs,zba,zbb,zbs,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicsr,zifencei,zihintntl,zihintpause,zihpm") }, + { str_lit("sifive-p670"), str_lit("64bit,a,auipc-addi-fusion,c,conditional-cmv-fusion,d,f,fast-unaligned-access,lui-addi-fusion,m,no-default-unroll,v,za64rs,zba,zbb,zbs,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicsr,zifencei,zihintntl,zihintpause,zihpm,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl128b,zvl32b,zvl64b") }, + { str_lit("sifive-s21"), str_lit("64bit,a,c,m,zicsr,zifencei") }, + { str_lit("sifive-s51"), str_lit("64bit,a,c,m,zicsr,zifencei") }, + { str_lit("sifive-s54"), str_lit("64bit,a,c,d,f,m,zicsr,zifencei") }, + { str_lit("sifive-s76"), str_lit("64bit,a,c,d,f,m,no-default-unroll,short-forward-branch-opt,sifive7,zicsr,zifencei,zihintpause") }, + { str_lit("sifive-u54"), str_lit("64bit,a,c,d,f,m,zicsr,zifencei") }, + { str_lit("sifive-u74"), str_lit("64bit,a,c,d,f,m,no-default-unroll,short-forward-branch-opt,sifive7,zicsr,zifencei") }, + { str_lit("sifive-x280"), str_lit("64bit,a,c,d,dlen-factor-2,f,m,no-default-unroll,short-forward-branch-opt,sifive7,v,zba,zbb,zfh,zfhmin,zicsr,zifencei,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvl128b,zvl256b,zvl32b,zvl512b,zvl64b") }, + { str_lit("syntacore-scr1-base"), str_lit("32bit,c,no-default-unroll,zicsr,zifencei") }, + { str_lit("syntacore-scr1-max"), str_lit("32bit,c,m,no-default-unroll,zicsr,zifencei") }, + { str_lit("veyron-v1"), str_lit("64bit,a,auipc-addi-fusion,c,d,f,ld-add-fusion,lui-addi-fusion,m,shifted-zextw-fusion,ventana-veyron,xventanacondops,zba,zbb,zbc,zbs,zexth-fusion,zextw-fusion,zicbom,zicbop,zicboz,zicntr,zicsr,zifencei,zihintpause,zihpm") }, + { str_lit("xiangshan-nanhu"), str_lit("64bit,a,c,d,f,m,svinval,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zicbom,zicboz,zicsr,zifencei,zkn,zknd,zkne,zknh,zksed,zksh") }, +}; diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index e5282f63e..1c4b88101 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -155,6 +155,11 @@ gb_internal bool does_require_msgSend_stret(Type *return_type) { return false; } + // No objc here so this doesn't matter, right? + if (build_context.metrics.arch == TargetArch_riscv64) { + return false; + } + // if (build_context.metrics.arch == TargetArch_arm32) { // i64 struct_limit = type_size_of(t_uintptr); // // NOTE(bill): This is technically wrong diff --git a/src/checker.cpp b/src/checker.cpp index c8eaf0acc..b24a7afdb 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1039,6 +1039,7 @@ gb_internal void init_universal(void) { {"arm64", TargetArch_arm64}, {"wasm32", TargetArch_wasm32}, {"wasm64p32", TargetArch_wasm64p32}, + {"riscv64", TargetArch_riscv64}, }; auto fields = add_global_enum_type(str_lit("Odin_Arch_Type"), values, gb_count_of(values)); diff --git a/src/linker.cpp b/src/linker.cpp index 046e72d0e..faca28932 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -388,6 +388,12 @@ gb_internal i32 linker_stage(LinkerData *gen) { } else { timings_start_section(timings, str_lit("ld-link")); + // Link using `clang`, unless overridden by `ODIN_CLANG_PATH` environment variable. + const char* clang_path = gb_get_env("ODIN_CLANG_PATH", permanent_allocator()); + if (clang_path == NULL) { + clang_path = "clang"; + } + // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe char cwd[256]; #if !defined(GB_SYSTEM_WINDOWS) @@ -458,7 +464,20 @@ gb_internal i32 linker_stage(LinkerData *gen) { } #endif // GB_ARCH_*_BIT - if (is_osx) { + if (build_context.metrics.arch == TargetArch_riscv64) { + result = system_exec_command_line_app("clang", + "%s \"%.*s\" " + "-c -o \"%.*s\" " + "-target %.*s -march=rv64gc " + "%.*s " + "", + clang_path, + LIT(asm_file), + LIT(obj_file), + LIT(build_context.metrics.target_triplet), + LIT(build_context.extra_assembler_flags) + ); + } else if (is_osx) { // `as` comes with MacOS. result = system_exec_command_line_app("as", "as \"%.*s\" " @@ -592,7 +611,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); } - } else if (build_context.metrics.os != TargetOs_openbsd && build_context.metrics.os != TargetOs_haiku) { + } else if (build_context.metrics.os != TargetOs_openbsd && build_context.metrics.os != TargetOs_haiku && build_context.metrics.arch != TargetArch_riscv64) { // OpenBSD and Haiku default to PIE executable. do not pass -no-pie for it. link_settings = gb_string_appendc(link_settings, "-no-pie "); } @@ -635,12 +654,6 @@ gb_internal i32 linker_stage(LinkerData *gen) { } } - // Link using `clang`, unless overridden by `ODIN_CLANG_PATH` environment variable. - const char* clang_path = gb_get_env("ODIN_CLANG_PATH", permanent_allocator()); - if (clang_path == NULL) { - clang_path = "clang"; - } - gbString link_command_line = gb_string_make(heap_allocator(), clang_path); defer (gb_string_free(link_command_line)); diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index c21cd0a46..0837e40bf 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -332,7 +332,8 @@ gb_internal i64 lb_alignof(LLVMTypeRef type) { } -#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, ProcCallingConvention calling_convention, Type *original_type) +#define LB_ABI_INFO(name) lbFunctionType *name(lbModule *m, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, ProcCallingConvention calling_convention, Type *original_type) +#define LB_ABI_INFO_CTX(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, ProcCallingConvention calling_convention, Type *original_type) typedef LB_ABI_INFO(lbAbiInfoType); #define LB_ABI_COMPUTE_RETURN_TYPE(name) lbArgType name(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple) @@ -379,7 +380,7 @@ namespace lbAbi386 { gb_internal Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count); gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type); - gb_internal LB_ABI_INFO(abi_info) { + gb_internal LB_ABI_INFO_CTX(abi_info) { lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); ft->ctx = c; ft->args = compute_arg_types(c, arg_types, arg_count); @@ -460,7 +461,7 @@ namespace lbAbiAmd64Win64 { gb_internal Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count); gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type); - gb_internal LB_ABI_INFO(abi_info) { + gb_internal LB_ABI_INFO_CTX(abi_info) { lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); ft->ctx = c; ft->args = compute_arg_types(c, arg_types, arg_count); @@ -570,7 +571,7 @@ namespace lbAbiAmd64SysV { gb_internal Array classify(LLVMTypeRef t); gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array const ®_classes, LLVMTypeRef type); - gb_internal LB_ABI_INFO(abi_info) { + gb_internal LB_ABI_INFO_CTX(abi_info) { lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); ft->ctx = c; ft->calling_convention = calling_convention; @@ -1008,7 +1009,7 @@ namespace lbAbiArm64 { gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type); gb_internal bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_); - gb_internal LB_ABI_INFO(abi_info) { + gb_internal LB_ABI_INFO_CTX(abi_info) { lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); ft->ctx = c; ft->args = compute_arg_types(c, arg_types, arg_count); @@ -1242,7 +1243,7 @@ namespace lbAbiWasm { enum {MAX_DIRECT_STRUCT_SIZE = 32}; - gb_internal LB_ABI_INFO(abi_info) { + gb_internal LB_ABI_INFO_CTX(abi_info) { lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); ft->ctx = c; ft->calling_convention = calling_convention; @@ -1407,7 +1408,7 @@ namespace lbAbiArm32 { gb_internal Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention); gb_internal lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined); - gb_internal LB_ABI_INFO(abi_info) { + gb_internal LB_ABI_INFO_CTX(abi_info) { lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); ft->ctx = c; ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention); @@ -1485,8 +1486,256 @@ namespace lbAbiArm32 { } }; +namespace lbAbiRiscv64 { + + gb_internal bool is_register(LLVMTypeRef type) { + LLVMTypeKind kind = LLVMGetTypeKind(type); + switch (kind) { + case LLVMIntegerTypeKind: + case LLVMHalfTypeKind: + case LLVMFloatTypeKind: + case LLVMDoubleTypeKind: + case LLVMPointerTypeKind: + return true; + } + return false; + } + + gb_internal bool is_float(LLVMTypeRef type) { + LLVMTypeKind kind = LLVMGetTypeKind(type); + switch (kind) { + case LLVMHalfTypeKind: + case LLVMFloatTypeKind: + case LLVMDoubleTypeKind: + return true; + default: + return false; + } + } + + gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) { + LLVMAttributeRef attr = nullptr; + LLVMTypeRef i1 = LLVMInt1TypeInContext(c); + if (type == i1) { + attr = lb_create_enum_attribute(c, "zeroext"); + } + return lb_arg_type_direct(type, nullptr, nullptr, attr); + } + + gb_internal void flatten(lbModule *m, Array *fields, LLVMTypeRef type, bool with_padding) { + LLVMTypeKind kind = LLVMGetTypeKind(type); + switch (kind) { + case LLVMStructTypeKind: { + if (LLVMIsPackedStruct(type)) { + array_add(fields, type); + break; + } + + if (!with_padding) { + auto field_remapping = map_get(&m->struct_field_remapping, cast(void *)type); + if (field_remapping) { + auto remap = *field_remapping; + for_array(i, remap) { + flatten(m, fields, LLVMStructGetTypeAtIndex(type, remap[i]), with_padding); + } + break; + } else { + debugf("no field mapping for type: %s\n", LLVMPrintTypeToString(type)); + } + } + + unsigned elem_count = LLVMCountStructElementTypes(type); + for (unsigned i = 0; i < elem_count; i += 1) { + flatten(m, fields, LLVMStructGetTypeAtIndex(type, i), with_padding); + } + break; + } + case LLVMArrayTypeKind: { + unsigned len = LLVMGetArrayLength(type); + LLVMTypeRef elem = OdinLLVMGetArrayElementType(type); + for (unsigned i = 0; i < len; i += 1) { + flatten(m, fields, elem, with_padding); + } + break; + } + default: + array_add(fields, type); + } + } + + gb_internal lbArgType compute_arg_type(lbModule *m, LLVMTypeRef type, int *gprs_left, int *fprs_left, Type *odin_type) { + LLVMContextRef c = m->ctx; + + int xlen = 8; // 8 byte int register size for riscv64. + + // NOTE: we are requiring both of these to be enabled so we can just hard-code 8. + // int flen = 0; + // if (check_target_feature_is_enabled(str_lit("d"), nullptr)) { + // flen = 8; // Double precision floats are enabled. + // } else if (check_target_feature_is_enabled(str_lit("f"), nullptr)) { + // flen = 4; // Single precision floats are enabled. + // } + int flen = 8; + + LLVMTypeKind kind = LLVMGetTypeKind(type); + i64 size = lb_sizeof(type); + + if (size == 0) { + return lb_arg_type_direct(type, LLVMStructTypeInContext(c, nullptr, 0, false), nullptr, nullptr); + } + + LLVMTypeRef orig_type = type; + + // Flatten down the type so it is easier to check all the ABI conditions. + // Note that we also need to remove all implicit padding fields Odin adds so we keep ABI + // compatibility for struct declarations. + if (kind == LLVMStructTypeKind && size <= gb_max(2*xlen, 2*flen)) { + Array fields = array_make(temporary_allocator(), 0, LLVMCountStructElementTypes(type)); + flatten(m, &fields, type, false); + + if (fields.count == 1) { + type = fields[0]; + } else { + type = LLVMStructTypeInContext(c, fields.data, cast(unsigned)fields.count, false); + } + + kind = LLVMGetTypeKind(type); + size = lb_sizeof(type); + GB_ASSERT_MSG(size == lb_sizeof(orig_type), "flattened: %s of size %d, original: %s of size %d", LLVMPrintTypeToString(type), size, LLVMPrintTypeToString(orig_type), lb_sizeof(orig_type)); + } + + if (is_float(type) && size <= flen && *fprs_left >= 1) { + *fprs_left -= 1; + return non_struct(c, orig_type); + } + + if (kind == LLVMStructTypeKind && size <= 2*flen) { + unsigned elem_count = LLVMCountStructElementTypes(type); + if (elem_count == 2) { + LLVMTypeRef ty1 = LLVMStructGetTypeAtIndex(type, 0); + i64 ty1s = lb_sizeof(ty1); + LLVMTypeRef ty2 = LLVMStructGetTypeAtIndex(type, 1); + i64 ty2s = lb_sizeof(ty2); + + if (is_float(ty1) && is_float(ty2) && ty1s <= flen && ty2s <= flen && *fprs_left >= 2) { + *fprs_left -= 2; + return lb_arg_type_direct(orig_type, type, nullptr, nullptr); + } + + if (is_float(ty1) && is_register(ty2) && ty1s <= flen && ty2s <= xlen && *fprs_left >= 1 && *gprs_left >= 1) { + *fprs_left -= 1; + *gprs_left -= 1; + return lb_arg_type_direct(orig_type, type, nullptr, nullptr); + } + + if (is_register(ty1) && is_float(ty2) && ty1s <= xlen && ty2s <= flen && *gprs_left >= 1 && *fprs_left >= 1) { + *fprs_left -= 1; + *gprs_left -= 1; + return lb_arg_type_direct(orig_type, type, nullptr, nullptr); + } + } + } + + // At this point all the cases for floating point registers are exhausted, fit it into + // integer registers or the stack. + // LLVM automatically handles putting args on the stack so we don't check the amount of registers that are left here. + + if (size <= xlen) { + *gprs_left -= 1; + if (is_register(type)) { + return non_struct(c, orig_type); + } else { + return lb_arg_type_direct(orig_type, LLVMIntTypeInContext(c, cast(unsigned)(size*8)), nullptr, nullptr); + } + } else if (size <= 2*xlen) { + LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, 2); + fields[0] = LLVMIntTypeInContext(c, cast(unsigned)(xlen*8)); + fields[1] = LLVMIntTypeInContext(c, cast(unsigned)((size-xlen)*8)); + + *gprs_left -= 2; + return lb_arg_type_direct(orig_type, LLVMStructTypeInContext(c, fields, 2, false), nullptr, nullptr); + } else { + return lb_arg_type_indirect(orig_type, nullptr); + } + } + + gb_internal Array compute_arg_types(lbModule *m, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention, Type *odin_type, int *gprs, int *fprs) { + auto args = array_make(lb_function_type_args_allocator(), arg_count); + + for (unsigned i = 0; i < arg_count; i++) { + LLVMTypeRef type = arg_types[i]; + args[i] = compute_arg_type(m, type, gprs, fprs, odin_type); + } + + return args; + } + + gb_internal lbArgType compute_return_type(lbFunctionType *ft, lbModule *m, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, Type *odin_type, int *agprs) { + LLVMContextRef c = m->ctx; + + if (!return_is_defined) { + return lb_arg_type_direct(LLVMVoidTypeInContext(c)); + } + + // There are two registers for return types. + int gprs = 2; + int fprs = 2; + lbArgType ret = compute_arg_type(m, return_type, &gprs, &fprs, odin_type); + + // Return didn't fit into the return registers, so caller allocates and it is returned via + // an out-pointer. + if (ret.kind == lbArg_Indirect) { + + // Transform multiple return into out pointers if possible. + if (return_is_tuple) { + if (lb_is_type_kind(return_type, LLVMStructTypeKind)) { + int field_count = cast(int)LLVMCountStructElementTypes(return_type); + if (field_count > 1 && field_count <= *agprs) { + ft->original_arg_count = ft->args.count; + ft->multiple_return_original_type = return_type; + + for (int i = 0; i < field_count-1; i++) { + LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(return_type, i); + LLVMTypeRef field_pointer_type = LLVMPointerType(field_type, 0); + lbArgType ret_partial = lb_arg_type_direct(field_pointer_type); + array_add(&ft->args, ret_partial); + *agprs -= 1; + } + GB_ASSERT(*agprs >= 0); + + // override the return type for the last field + LLVMTypeRef new_return_type = LLVMStructGetTypeAtIndex(return_type, field_count-1); + return compute_return_type(ft, m, new_return_type, true, false, odin_type, agprs); + } + } + } + + LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", ret.type); + return lb_arg_type_indirect(ret.type, attr); + } + + return ret; + } + + gb_internal LB_ABI_INFO(abi_info) { + lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType); + ft->ctx = m->ctx; + ft->calling_convention = calling_convention; + + int gprs = 8; + int fprs = 8; + + ft->args = compute_arg_types(m, arg_types, arg_count, calling_convention, original_type, &gprs, &fprs); + ft->ret = compute_return_type(ft, m, return_type, return_is_defined, return_is_tuple, original_type, &gprs); + + return ft; + } +} + gb_internal LB_ABI_INFO(lb_get_abi_info_internal) { + LLVMContextRef c = m->ctx; + switch (calling_convention) { case ProcCC_None: case ProcCC_InlineAsm: @@ -1534,6 +1783,8 @@ gb_internal LB_ABI_INFO(lb_get_abi_info_internal) { return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type); case TargetArch_wasm64p32: return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type); + case TargetArch_riscv64: + return lbAbiRiscv64::abi_info(m, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type); } GB_PANIC("Unsupported ABI"); @@ -1543,7 +1794,7 @@ gb_internal LB_ABI_INFO(lb_get_abi_info_internal) { gb_internal LB_ABI_INFO(lb_get_abi_info) { lbFunctionType *ft = lb_get_abi_info_internal( - c, + m, arg_types, arg_count, return_type, return_is_defined, ALLOW_SPLIT_MULTI_RETURNS && return_is_tuple && is_calling_convention_odin(calling_convention), @@ -1555,7 +1806,7 @@ gb_internal LB_ABI_INFO(lb_get_abi_info) { // This is to make it consistent when and how it is handled if (calling_convention == ProcCC_Odin) { // append the `context` pointer - lbArgType context_param = lb_arg_type_direct(LLVMPointerType(LLVMInt8TypeInContext(c), 0)); + lbArgType context_param = lb_arg_type_direct(LLVMPointerType(LLVMInt8TypeInContext(m->ctx), 0)); array_add(&ft->args, context_param); } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 72ba12516..f852636a6 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -40,7 +40,10 @@ String get_default_microarchitecture() { default_march = str_lit("x86-64-v2"); } } + } else if (build_context.metrics.arch == TargetArch_riscv64) { + default_march = str_lit("generic-rv64"); } + return default_march; } @@ -65,13 +68,33 @@ gb_internal String get_default_features() { } String microarch = get_final_microarchitecture(); + + // NOTE(laytan): for riscv64 to work properly with Odin, we need to enforce some features. + // and we also overwrite the generic target to include more features so we don't default to + // a potato feature set. + if (bc->metrics.arch == TargetArch_riscv64) { + if (microarch == str_lit("generic-rv64")) { + // This is what clang does by default (on -march=rv64gc for General Computing), seems good to also default to. + String features = str_lit("64bit,a,c,d,f,m,relax,zicsr,zifencei"); + + // Update the features string so LLVM uses it later. + if (bc->target_features_string.len > 0) { + bc->target_features_string = concatenate3_strings(permanent_allocator(), features, str_lit(","), bc->target_features_string); + } else { + bc->target_features_string = features; + } + + return features; + } + } + for (int i = off; i < off+target_microarch_counts[bc->metrics.arch]; i += 1) { if (microarch_features_list[i].microarch == microarch) { return microarch_features_list[i].features; } } - GB_PANIC("unknown microarch"); + GB_PANIC("unknown microarch: %.*s", LIT(microarch)); return {}; } @@ -3030,6 +3053,12 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { // Always use PIC for OpenBSD and Haiku: they default to PIE reloc_mode = LLVMRelocPIC; } + + if (build_context.metrics.arch == TargetArch_riscv64) { + // NOTE(laytan): didn't seem to work without this. + reloc_mode = LLVMRelocPIC; + } + break; case RelocMode_Static: reloc_mode = LLVMRelocStatic; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b5338297e..842a1cbc8 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1787,7 +1787,7 @@ gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *t } } GB_ASSERT(param_index == param_count); - lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, return_is_tuple, type->Proc.calling_convention, type); + lbFunctionType *ft = lb_get_abi_info(m, params, param_count, ret, ret != nullptr, return_is_tuple, type->Proc.calling_convention, type); { for_array(j, ft->args) { auto arg = ft->args[j]; @@ -2114,6 +2114,12 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { llvm_type = LLVMStructCreateNamed(ctx, name); map_set(&m->types, type, llvm_type); lb_clone_struct_type(llvm_type, lb_type(m, base)); + + if (base->kind == Type_Struct) { + map_set(&m->struct_field_remapping, cast(void *)llvm_type, lb_get_struct_remapping(m, base)); + map_set(&m->struct_field_remapping, cast(void *)type, lb_get_struct_remapping(m, base)); + } + return llvm_type; } } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 3326b4041..e850d3364 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2877,6 +2877,31 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu LLVMValueRef inline_asm = nullptr; switch (build_context.metrics.arch) { + case TargetArch_riscv64: + { + GB_ASSERT(arg_count <= 7); + + char asm_string[] = "ecall"; + gbString constraints = gb_string_make(heap_allocator(), "={a0}"); + for (unsigned i = 0; i < arg_count; i++) { + constraints = gb_string_appendc(constraints, ",{"); + static char const *regs[] = { + "a7", + "a0", + "a1", + "a2", + "a3", + "a4", + "a5", + "a6" + }; + constraints = gb_string_appendc(constraints, regs[i]); + constraints = gb_string_appendc(constraints, "}"); + } + + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); + } + break; case TargetArch_amd64: { GB_ASSERT(arg_count <= 7); diff --git a/src/main.cpp b/src/main.cpp index 77758b929..5131bdc21 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3245,6 +3245,15 @@ int main(int arg_count, char const **arg_ptr) { } } + // NOTE(laytan): on riscv64 we want to enforce some features. + if (build_context.metrics.arch == TargetArch_riscv64) { + String disabled; + if (!check_target_feature_is_enabled(str_lit("64bit,f,d,m"), &disabled)) { // 64bit, floats, doubles, integer multiplication. + gb_printf_err("missing required target feature: \"%.*s\", enable it by setting a different -microarch or explicitly adding it through -target-features\n", LIT(disabled)); + gb_exit(1); + } + } + if (build_context.show_debug_messages) { debugf("Selected microarch: %.*s\n", LIT(march)); debugf("Default microarch features: %.*s\n", LIT(default_features)); -- cgit v1.2.3 From d0eaf7642dcf38f6f98c50e4daa53d31e2fadd71 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 14:36:18 +0100 Subject: Add `intrinsics.type_has_shared_fields` --- base/intrinsics/intrinsics.odin | 2 ++ src/check_builtin.cpp | 53 +++++++++++++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 3 +++ 3 files changed, 58 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index b7e8c1189..3cf99bbd2 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -219,6 +219,8 @@ type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info --- type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) --- type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) --- +type_has_shared_fields :: proc($U, $V: typeid) -> bool typeid where type_is_struct(U), type_is_struct(V) --- + constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- constant_log2 :: proc($v: $T) -> T where type_is_integer(T) --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 1c4b88101..fa03da946 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5665,6 +5665,59 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } break; + + case BuiltinProc_type_has_shared_fields: + { + Type *u = check_type(c, ce->args[0]); + Type *ut = base_type(u); + if (ut == nullptr || ut == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (ut->kind != Type_Struct || ut->Struct.soa_kind != StructSoa_None) { + gbString t = type_to_string(ut); + error(ce->args[0], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + Type *v = check_type(c, ce->args[1]); + Type *vt = base_type(v); + if (vt == nullptr || vt == t_invalid) { + error(ce->args[1], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (vt->kind != Type_Struct || vt->Struct.soa_kind != StructSoa_None) { + gbString t = type_to_string(vt); + error(ce->args[1], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + bool is_shared = true; + + for (Entity *v_field : vt->Struct.fields) { + bool found = false; + for (Entity *u_field : ut->Struct.fields) { + if (v_field->token.string == u_field->token.string && + are_types_identical(v_field->type, u_field->type)) { + found = true; + break; + } + } + + if (!found) { + is_shared = false; + break; + } + } + + operand->mode = Addressing_Constant; + operand->value = exact_value_bool(is_shared); + operand->type = t_untyped_bool; + break; + } + case BuiltinProc_type_field_type: { Operand op = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index ef07938c7..300397be9 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -313,6 +313,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_map_info, BuiltinProc_type_map_cell_info, + BuiltinProc_type_has_shared_fields, + BuiltinProc__type_end, BuiltinProc_procedure_of, @@ -647,6 +649,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_map_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_map_cell_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_has_shared_fields"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From d299d4e1cd009a66ce72371b4e7ab6c61811f9fc Mon Sep 17 00:00:00 2001 From: Laytan Date: Sun, 25 Aug 2024 21:15:25 +0200 Subject: riscv: add an error when atomics are used without the atomics extension --- src/check_builtin.cpp | 8 ++++++++ src/checker_builtin_procs.hpp | 4 ++++ 2 files changed, 12 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index fa03da946..3742caeda 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2048,6 +2048,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return ok; } + if (BuiltinProc__atomic_begin < id && id < BuiltinProc__atomic_end) { + if (build_context.metrics.arch == TargetArch_riscv64) { + if (!check_target_feature_is_enabled(str_lit("a"), nullptr)) { + error(call, "missing required target feature \"a\" for atomics, enable it by setting a different -microarch or explicitly adding it through -target-features"); + } + } + } + switch (id) { default: GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name)); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 300397be9..2dfd570e4 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -99,6 +99,7 @@ enum BuiltinProcId { BuiltinProc_prefetch_write_instruction, BuiltinProc_prefetch_write_data, +BuiltinProc__atomic_begin, BuiltinProc_atomic_type_is_lock_free, BuiltinProc_atomic_thread_fence, BuiltinProc_atomic_signal_fence, @@ -124,6 +125,7 @@ enum BuiltinProcId { BuiltinProc_atomic_compare_exchange_strong_explicit, BuiltinProc_atomic_compare_exchange_weak, BuiltinProc_atomic_compare_exchange_weak_explicit, +BuiltinProc__atomic_end, BuiltinProc_fixed_point_mul, BuiltinProc_fixed_point_div, @@ -438,6 +440,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("prefetch_write_instruction"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("prefetch_write_data"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_type_is_lock_free"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_thread_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_signal_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, @@ -463,6 +466,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("atomic_compare_exchange_strong_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("atomic_compare_exchange_weak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("atomic_compare_exchange_weak_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("fixed_point_mul"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("fixed_point_div"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From a4ac50a5b455a4ebc21806d4b9e0529b8a4b796c Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 31 Aug 2024 19:06:17 +0200 Subject: Check for `#assert` condition to be a constant bool Fixes #4170 --- src/check_builtin.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 3742caeda..d2ad304bc 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1792,7 +1792,17 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count); return false; } - if (!is_type_boolean(operand->type) || operand->mode != Addressing_Constant) { + + // operand->type can be nil if the condition is a procedure, for example: #assert(assert()) + // So let's check it before we use it, so we get the same error as if we wrote `#exists(assert()) + Ast *arg = ce->args[0]; + Entity *e = nullptr; + Operand o = {}; + if (arg->kind == Ast_Ident) { + e = check_ident(c, &o, arg, nullptr, nullptr, true); + } + + if (operand->type == nullptr || !is_type_boolean(operand->type) || operand->mode != Addressing_Constant) { gbString str = expr_to_string(ce->args[0]); error(call, "'%s' is not a constant boolean", str); gb_string_free(str); -- cgit v1.2.3 From c1cb1a3d7e546bcb73a012eda04521d1adbb6366 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 31 Aug 2024 19:13:37 +0200 Subject: Simplified #assert check --- src/check_builtin.cpp | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index d2ad304bc..910e7ffdb 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1795,13 +1795,6 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o // operand->type can be nil if the condition is a procedure, for example: #assert(assert()) // So let's check it before we use it, so we get the same error as if we wrote `#exists(assert()) - Ast *arg = ce->args[0]; - Entity *e = nullptr; - Operand o = {}; - if (arg->kind == Ast_Ident) { - e = check_ident(c, &o, arg, nullptr, nullptr, true); - } - if (operand->type == nullptr || !is_type_boolean(operand->type) || operand->mode != Addressing_Constant) { gbString str = expr_to_string(ce->args[0]); error(call, "'%s' is not a constant boolean", str); -- cgit v1.2.3 From 490f8c15680ef62c4180940d8a41711a92cbdb0c Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 5 Sep 2024 15:55:55 +0200 Subject: add fixed point sign extend to 128 int deps --- src/check_builtin.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 910e7ffdb..888aa074d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5203,6 +5203,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } + if (sz >= 64) { + if (is_type_unsigned(x.type)) { + add_package_dependency(c, "runtime", "umodti3", true); + add_package_dependency(c, "runtime", "udivti3", true); + } else { + add_package_dependency(c, "runtime", "modti3", true); + add_package_dependency(c, "runtime", "divti3", true); + } + } + operand->type = x.type; operand->mode = Addressing_Value; } -- cgit v1.2.3 From 603efa860a5631f1708f6761d753146b6d47b4ba Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 14 Sep 2024 21:43:25 +0200 Subject: add '#caller_expression' --- base/runtime/core_builtin.odin | 4 +-- core/odin/parser/parser.odin | 10 +++++++ core/testing/testing.odin | 12 +++++--- src/check_builtin.cpp | 16 +++++++++++ src/check_expr.cpp | 7 ++++- src/check_type.cpp | 32 ++++++++++++++++++++++ src/entity.cpp | 1 + src/llvm_backend.hpp | 2 +- src/llvm_backend_proc.cpp | 62 ++++++++++++++++++++++++++++++++++++++---- 9 files changed, 133 insertions(+), 13 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index 8157afe09..67d249d11 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -913,7 +913,7 @@ card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int { @builtin @(disabled=ODIN_DISABLE_ASSERT) -assert :: proc(condition: bool, message := "", loc := #caller_location) { +assert :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) { if !condition { // NOTE(bill): This is wrapped in a procedure call // to improve performance to make the CPU not @@ -952,7 +952,7 @@ unimplemented :: proc(message := "", loc := #caller_location) -> ! { @builtin @(disabled=ODIN_DISABLE_ASSERT) -assert_contextless :: proc "contextless" (condition: bool, message := "", loc := #caller_location) { +assert_contextless :: proc "contextless" (condition: bool, message := #caller_expression(condition), loc := #caller_location) { if !condition { // NOTE(bill): This is wrapped in a procedure call // to improve performance to make the CPU not diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index aab59c29d..6f42c17db 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2277,6 +2277,16 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { bd.name = name.text return bd + case "caller_expression": + bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name)) + bd.tok = tok + bd.name = name.text + + if peek_token_kind(p, .Open_Paren) { + return parse_call_expr(p, bd) + } + return bd + case "location", "exists", "load", "load_directory", "load_hash", "hash", "assert", "panic", "defined", "config": bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name)) bd.tok = tok diff --git a/core/testing/testing.odin b/core/testing/testing.odin index d5e7c6830..09bf6dc0e 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -105,9 +105,13 @@ cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) { append(&t.cleanups, Internal_Cleanup{procedure, user_data, context}) } -expect :: proc(t: ^T, ok: bool, msg: string = "", loc := #caller_location) -> bool { +expect :: proc(t: ^T, ok: bool, msg := "", expr := #caller_expression(ok), loc := #caller_location) -> bool { if !ok { - log.error(msg, location=loc) + if msg == "" { + log.errorf("expected %v to be true", expr, location=loc) + } else { + log.error(msg, location=loc) + } } return ok } @@ -119,10 +123,10 @@ expectf :: proc(t: ^T, ok: bool, format: string, args: ..any, loc := #caller_loc return ok } -expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) { +expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location, value_expr := #caller_expression(value)) -> bool where intrinsics.type_is_comparable(T) { ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected) if !ok { - log.errorf("expected %v, got %v", expected, value, location=loc) + log.errorf("expected %v to be %v, got %v", value_expr, expected, value, location=loc) } return ok } diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 888aa074d..909eb668e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1632,6 +1632,22 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o operand->type = t_source_code_location; operand->mode = Addressing_Value; + } else if (name == "caller_expression") { + if (ce->args.count > 1) { + error(ce->args[0], "'#caller_expression' expects either 0 or 1 arguments, got %td", ce->args.count); + } + if (ce->args.count > 0) { + Ast *arg = ce->args[0]; + Operand o = {}; + Entity *e = check_ident(c, &o, arg, nullptr, nullptr, true); + if (e == nullptr || (e->flags & EntityFlag_Param) == 0) { + error(ce->args[0], "'#caller_expression' expected a valid earlier parameter name"); + } + arg->Ident.entity = e; + } + + operand->type = t_string; + operand->mode = Addressing_Value; } else if (name == "exists") { if (ce->args.count != 1) { error(ce->close, "'#exists' expects 1 argument, got %td", ce->args.count); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7f82fb58a..6776094bf 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7807,7 +7807,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c name == "load" || name == "load_directory" || name == "load_hash" || - name == "hash" + name == "hash" || + name == "caller_expression" ) { operand->mode = Addressing_Builtin; operand->builtin_id = BuiltinProc_DIRECTIVE; @@ -8725,6 +8726,10 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A error(node, "#caller_location may only be used as a default argument parameter"); o->type = t_source_code_location; o->mode = Addressing_Value; + } else if (name == "caller_expression") { + error(node, "#caller_expression may only be used as a default argument parameter"); + o->type = t_string; + o->mode = Addressing_Value; } else { if (name == "location") { init_core_source_code_location(c->checker); diff --git a/src/check_type.cpp b/src/check_type.cpp index 3767f7666..f0e0acb9b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1605,6 +1605,25 @@ gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) { return false; } +gb_internal bool is_caller_expression(Ast *expr) { + if (expr->kind == Ast_BasicDirective && expr->BasicDirective.name.string == "caller_expression") { + return true; + } + + Ast *call = unparen_expr(expr); + if (call->kind != Ast_CallExpr) { + return false; + } + + ast_node(ce, CallExpr, call); + if (ce->proc->kind != Ast_BasicDirective) { + return false; + } + + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + return name == "caller_expression"; +} gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location) { ParameterValue param_value = {}; @@ -1626,7 +1645,19 @@ gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_ if (in_type) { check_assignment(ctx, &o, in_type, str_lit("parameter value")); } + } else if (is_caller_expression(expr)) { + if (expr->kind != Ast_BasicDirective) { + check_builtin_procedure_directive(ctx, &o, expr, t_string); + } + + param_value.kind = ParameterValue_Expression; + o.type = t_string; + o.mode = Addressing_Value; + o.expr = expr; + if (in_type) { + check_assignment(ctx, &o, in_type, str_lit("parameter value")); + } } else { if (in_type) { check_expr_with_type_hint(ctx, &o, expr, in_type); @@ -1858,6 +1889,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para case ParameterValue_Nil: break; case ParameterValue_Location: + case ParameterValue_Expression: case ParameterValue_Value: gbString str = type_to_string(type); error(params[i], "A default value for a parameter must not be a polymorphic constant type, got %s", str); diff --git a/src/entity.cpp b/src/entity.cpp index db6ffdd52..0c4a20df4 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -104,6 +104,7 @@ enum ParameterValueKind { ParameterValue_Constant, ParameterValue_Nil, ParameterValue_Location, + ParameterValue_Expression, ParameterValue_Value, }; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 29d2ccfe6..68f95cb03 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -528,7 +528,7 @@ gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValu gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos); gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String const &procedure, TokenPos const &pos); -gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos); +gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TypeProc *procedure_type, Ast *call_expression); gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type); gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index e850d3364..d84599eb0 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -699,7 +699,9 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { } if (e->Variable.param_value.kind != ParameterValue_Invalid) { - lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos); + GB_ASSERT(e->Variable.param_value.kind != ParameterValue_Location); + GB_ASSERT(e->Variable.param_value.kind != ParameterValue_Expression); + lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, nullptr, nullptr); lb_addr_store(p, res, c); } @@ -3420,7 +3422,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } -gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos) { +gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TypeProc *procedure_type, Ast* call_expression) { switch (param_value.kind) { case ParameterValue_Constant: if (is_type_constant_type(parameter_type)) { @@ -3446,8 +3448,60 @@ gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, if (p->entity != nullptr) { proc_name = p->entity->token.string; } + + ast_node(ce, CallExpr, call_expression); + TokenPos pos = ast_token(ce->proc).pos; + return lb_emit_source_code_location_as_global(p, proc_name, pos); } + case ParameterValue_Expression: + { + Ast *orig = param_value.original_ast_expr; + if (orig->kind == Ast_BasicDirective) { + gbString expr = expr_to_string(call_expression, temporary_allocator()); + return lb_const_string(p->module, make_string_c(expr)); + } + + isize param_idx = -1; + String param_str = {0}; + { + Ast *call = unparen_expr(orig); + GB_ASSERT(call->kind == Ast_CallExpr); + ast_node(ce, CallExpr, call); + GB_ASSERT(ce->proc->kind == Ast_BasicDirective); + GB_ASSERT(ce->args.count == 1); + Ast *target = ce->args[0]; + GB_ASSERT(target->kind == Ast_Ident); + String target_str = target->Ident.token.string; + + param_idx = lookup_procedure_parameter(procedure_type, target_str); + param_str = target_str; + } + GB_ASSERT(param_idx >= 0); + + + Ast *target_expr = nullptr; + ast_node(ce, CallExpr, call_expression); + + if (ce->split_args->positional.count > param_idx) { + target_expr = ce->split_args->positional[param_idx]; + } + + for_array(i, ce->split_args->named) { + Ast *arg = ce->split_args->named[i]; + ast_node(fv, FieldValue, arg); + GB_ASSERT(fv->field->kind == Ast_Ident); + String name = fv->field->Ident.token.string; + if (name == param_str) { + target_expr = fv->value; + break; + } + } + + gbString expr = expr_to_string(target_expr, temporary_allocator()); + return lb_const_string(p->module, make_string_c(expr)); + } + case ParameterValue_Value: return lb_build_expr(p, param_value.ast_value); } @@ -3739,8 +3793,6 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } } - TokenPos pos = ast_token(ce->proc).pos; - if (pt->params != nullptr) { isize min_count = pt->params->Tuple.variables.count; @@ -3764,7 +3816,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { args[arg_index] = lb_const_nil(p->module, e->type); break; case Entity_Variable: - args[arg_index] = lb_handle_param_value(p, e->type, e->Variable.param_value, pos); + args[arg_index] = lb_handle_param_value(p, e->type, e->Variable.param_value, pt, expr); break; case Entity_Constant: -- cgit v1.2.3 From 9456c366848226d300ea5064c225084e7f9d55ad Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:18:48 -0400 Subject: Specify integer-like only for some `atomic_*` intrinsics Fixes #4256 --- src/check_builtin.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 909eb668e..8c051cca2 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4969,16 +4969,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As check_assignment(c, &x, elem, builtin_name); Type *t = type_deref(operand->type); - switch (id) { - case BuiltinProc_atomic_add: - case BuiltinProc_atomic_sub: - if (!is_type_numeric(t)) { + if (id != BuiltinProc_atomic_exchange) { + if (!is_type_integer_like(t)) { gbString str = type_to_string(t); - error(operand->expr, "Expected a numeric type for '%.*s', got %s", LIT(builtin_name), str); + error(operand->expr, "Expected an integer type for '%.*s', got %s", LIT(builtin_name), str); gb_string_free(str); } else if (is_type_different_to_arch_endianness(t)) { gbString str = type_to_string(t); - error(operand->expr, "Expected a numeric type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str); + error(operand->expr, "Expected an integer type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str); gb_string_free(str); } } @@ -5014,19 +5012,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } Type *t = type_deref(operand->type); - switch (id) { - case BuiltinProc_atomic_add_explicit: - case BuiltinProc_atomic_sub_explicit: - if (!is_type_numeric(t)) { + if (id != BuiltinProc_atomic_exchange_explicit) { + if (!is_type_integer_like(t)) { gbString str = type_to_string(t); - error(operand->expr, "Expected a numeric type for '%.*s', got %s", LIT(builtin_name), str); + error(operand->expr, "Expected an integer type for '%.*s', got %s", LIT(builtin_name), str); gb_string_free(str); } else if (is_type_different_to_arch_endianness(t)) { gbString str = type_to_string(t); - error(operand->expr, "Expected a numeric type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str); + error(operand->expr, "Expected an integer type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str); gb_string_free(str); } - break; } operand->type = elem; -- cgit v1.2.3 From 53bb6c85f71cd2555c49363505b7323382372b94 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 2 Oct 2024 15:48:58 +0100 Subject: `a ordered` to `an ordered` --- src/check_builtin.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8c051cca2..ab18123dd 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3098,7 +3098,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); - error(call, "Expected a ordered numeric type to 'min', got '%s'", type_str); + error(call, "Expected an ordered numeric type to 'min', got '%s'", type_str); gb_string_free(type_str); return false; } @@ -3184,7 +3184,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) { gbString type_str = type_to_string(b.type); error(call, - "Expected a ordered numeric type to 'min', got '%s'", + "Expected an ordered numeric type to 'min', got '%s'", type_str); gb_string_free(type_str); return false; @@ -3267,7 +3267,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As // Okay } else if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(original_type); - error(call, "Expected a ordered numeric type to 'max', got '%s'", type_str); + error(call, "Expected an ordered numeric type to 'max', got '%s'", type_str); gb_string_free(type_str); return false; } @@ -3358,7 +3358,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (!is_type_ordered(b.type) || !(is_type_numeric(b.type) || is_type_string(b.type))) { gbString type_str = type_to_string(b.type); error(arg, - "Expected a ordered numeric type to 'max', got '%s'", + "Expected an ordered numeric type to 'max', got '%s'", type_str); gb_string_free(type_str); return false; @@ -3488,7 +3488,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *type = operand->type; if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(operand->type); - error(call, "Expected a ordered numeric or string type to 'clamp', got '%s'", type_str); + error(call, "Expected an ordered numeric or string type to 'clamp', got '%s'", type_str); gb_string_free(type_str); return false; } @@ -3505,7 +3505,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } if (!is_type_ordered(y.type) || !(is_type_numeric(y.type) || is_type_string(y.type))) { gbString type_str = type_to_string(y.type); - error(call, "Expected a ordered numeric or string type to 'clamp', got '%s'", type_str); + error(call, "Expected an ordered numeric or string type to 'clamp', got '%s'", type_str); gb_string_free(type_str); return false; } @@ -3516,7 +3516,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } if (!is_type_ordered(z.type) || !(is_type_numeric(z.type) || is_type_string(z.type))) { gbString type_str = type_to_string(z.type); - error(call, "Expected a ordered numeric or string type to 'clamp', got '%s'", type_str); + error(call, "Expected an ordered numeric or string type to 'clamp', got '%s'", type_str); gb_string_free(type_str); return false; } -- cgit v1.2.3 From 6ef915c312f210e5dac9559e863e58886989a1da Mon Sep 17 00:00:00 2001 From: Misomosi Date: Sun, 20 Oct 2024 22:51:39 -0400 Subject: Fixes #4395 by not assuming simd returns val --- src/check_builtin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index ab18123dd..09e558500 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2060,8 +2060,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As bool ok = check_builtin_simd_operation(c, operand, call, id, type_hint); if (!ok) { operand->type = t_invalid; + operand->mode = Addressing_Value; } - operand->mode = Addressing_Value; operand->value = {}; operand->expr = call; return ok; -- cgit v1.2.3 From e064f8c6bec2e656446b52afb35af7bfee02e6a9 Mon Sep 17 00:00:00 2001 From: Laytan Date: Mon, 28 Oct 2024 18:58:26 +0100 Subject: fix `#load_directory` including nested directories --- src/check_builtin.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index ab18123dd..ebdfa41b0 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1533,6 +1533,10 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c for (FileInfo fi : list) { LoadFileCache *cache = nullptr; + if (fi.is_dir) { + continue; + } + if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache, LoadFileTier_Contents, /*use_mutex*/false)) { array_add(&file_caches, cache); } else { -- cgit v1.2.3 From 71880eb1fff836b222fa2e98adecb52b3382edca Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Sun, 17 Nov 2024 21:02:30 +0100 Subject: report error when builtin min/max has 1 (non-type) param --- src/check_builtin.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 42b9e2180..c86503093 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3170,6 +3170,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } + if (ce->args.count <= 1) { + error(call, "Too few arguments for 'min', two or more are required"); + return false; + } bool all_constant = operand->mode == Addressing_Constant; @@ -3343,6 +3347,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As gb_string_free(type_str); return false; } + + if (ce->args.count <= 1) { + error(call, "Too few arguments for 'max', two or more are required"); + return false; + } bool all_constant = operand->mode == Addressing_Constant; -- cgit v1.2.3 From 7c3ce334d6914f73165eb66e253a2176c77d69d6 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 25 Nov 2024 15:27:35 +0100 Subject: Fix #4508 for abs, min, max (#4516) * Fix #4508 for abs, min, max and the rest of the builtins. None of these segfault now: ```odin package bug main :: proc() { p :: proc() {} // _ = len(p()) // _ = cap(p()) // _ = size_of(p()) // _ = align_of(p()) // T :: struct {} // _ = offset_of(p()) // _ = offset_of(T, p()) // _ = offset_of(p(), foo) // _ = offset_of(p(), "") // _ = type_of(p()) // _ = type_info_of(p()) // _ = typeid_of(p()) // A: [4]int // _ = swizzle(p()) // :: proc(x: [N]T, indices: ..int) -> [len(indices)]T --- // _ = swizzle(A, p()) // :: proc(x: [N]T, indices: ..int) -> [len(indices)]T --- // _ = complex(p(), p()) // _ = quaternion(p(), p(), p(), p()) // _ = quaternion(w=p(), x=p(), y=p(), z=p()) // _ = real(p()) // _ = imag(p()) // _ = jmag(p()) // _ = kmag(p()) // _ = conj(p()) // _ = expand_values(p()) // _ = min(p()) // _ = max(p()) // _ = abs(p()) // _ = clamp(p(), p(), p()) // _ = soa_zip(p()) // _ = soa_unzip(p()) } ``` --- src/check_builtin.cpp | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'src/check_builtin.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c86503093..ea902387b 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2551,6 +2551,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_swizzle: { // swizzle :: proc(v: [N]T, ..int) -> [M]T + if (!operand->type) { + return false; + } + Type *original_type = operand->type; Type *type = base_type(original_type); i64 max_count = 0; @@ -2908,6 +2912,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As // imag :: proc(x: type) -> float_type Operand *x = operand; + if (!x->type) { + return false; + } + if (is_type_untyped(x->type)) { if (x->mode == Addressing_Constant) { if (is_type_numeric(x->type)) { @@ -2968,6 +2976,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As // kmag :: proc(x: type) -> float_type Operand *x = operand; + if (!x->type) { + return false; + } + if (is_type_untyped(x->type)) { if (x->mode == Addressing_Constant) { if (is_type_numeric(x->type)) { @@ -3017,6 +3029,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_conj: { // conj :: proc(x: type) -> type Operand *x = operand; + if (!x->type) { + return false; + } + Type *t = x->type; Type *elem = core_array_type(t); @@ -3057,10 +3073,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } case BuiltinProc_expand_values: { + if (!operand->type) { + return false; + } + Type *type = base_type(operand->type); if (!is_type_struct(type) && !is_type_array(type)) { gbString type_str = type_to_string(operand->type); - error(call, "Expected a struct or array type, got '%s'", type_str); + error(call, "Expected a struct or array type to 'expand_values', got '%s'", type_str); gb_string_free(type_str); return false; } @@ -3096,8 +3116,13 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As check_multi_expr_or_type(c, operand, ce->args[0]); + if (!operand->type) { + return false; + } + Type *original_type = operand->type; Type *type = base_type(operand->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))) { @@ -3268,6 +3293,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As check_multi_expr_or_type(c, operand, ce->args[0]); + if (!operand->type) { + return false; + } + Type *original_type = operand->type; Type *type = base_type(operand->type); @@ -3443,6 +3472,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_abs: { // abs :: proc(n: numeric) -> numeric + if (!operand->type) { + return false; + } + if (!(is_type_numeric(operand->type) && !is_type_array(operand->type))) { gbString type_str = type_to_string(operand->type); error(call, "Expected a numeric type to 'abs', got '%s'", type_str); @@ -3498,6 +3531,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_clamp: { // clamp :: proc(a, min, max: ordered) -> ordered + if (!operand->type) { + return false; + } + Type *type = operand->type; if (!is_type_ordered(type) || !(is_type_numeric(type) || is_type_string(type))) { gbString type_str = type_to_string(operand->type); -- cgit v1.2.3