From 9e5e49a65daf1f189e49c0eade7d90d148e7ac71 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 14 Nov 2023 16:53:30 +0100 Subject: checker: suggest ..[]T when passing a slice to variadic arg ..T --- src/check_expr.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5cc548739..5a8b57df6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5652,6 +5652,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } else { if (show_error) { check_assignment(c, o, param_type, str_lit("procedure argument")); + + Type *src = base_type(o->type); + Type *dst = base_type(param_type); + if (is_type_slice(src) && are_types_identical(src->Slice.elem, dst)) { + gbString a = expr_to_string(o->expr); + error_line("\tSuggestion: Did you mean to pass the slice into the variadic parameter with ..%s?\n\n", a); + gb_string_free(a); + } } err = CallArgumentError_WrongTypes; } -- cgit v1.2.3 From 4c1a9d2b3f821733ac79135c76e13d3be6f3ed4f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 23 Nov 2023 16:56:18 +0000 Subject: Fix `&x[i]` of `^#soa` types --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5a8b57df6..7b90677c8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2339,7 +2339,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * ast_node(ue, UnaryExpr, node); if (ast_node_expect(ue->expr, Ast_IndexExpr)) { ast_node(ie, IndexExpr, ue->expr); - Type *soa_type = type_of_expr(ie->expr); + Type *soa_type = type_deref(type_of_expr(ie->expr)); GB_ASSERT(is_type_soa_struct(soa_type)); o->type = alloc_type_soa_pointer(soa_type); } else { @@ -7428,7 +7428,7 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count = t->Struct.soa_count; } o->type = t->Struct.soa_elem; - if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable) { + if (o->mode == Addressing_SoaVariable || o->mode == Addressing_Variable || indirection) { o->mode = Addressing_SoaVariable; } else { o->mode = Addressing_Value; -- cgit v1.2.3 From e78ee90ac229468e88281fece02b752cc8160744 Mon Sep 17 00:00:00 2001 From: jakubtomsu <66876057+jakubtomsu@users.noreply.github.com> Date: Thu, 23 Nov 2023 20:58:26 +0100 Subject: Remove code that skipped checking blank params --- src/check_expr.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7b90677c8..71accfb81 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5606,9 +5606,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A for (isize i = 0; i < pt->param_count; i++) { if (!visited[i]) { Entity *e = pt->params->Tuple.variables[i]; - if (is_blank_ident(e->token)) { - continue; - } if (e->kind == Entity_Variable) { if (e->Variable.param_value.kind != ParameterValue_Invalid) { ordered_operands[i].mode = Addressing_Value; -- cgit v1.2.3 From 2820bbc269bb989052163544f2764bc4287254e4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Jan 2024 13:38:30 +0000 Subject: Add `@(entry_point_only)` for procedures --- src/check_decl.cpp | 1 + src/check_expr.cpp | 8 ++++++++ src/checker.cpp | 3 +++ src/checker.hpp | 1 + src/entity.cpp | 1 + 5 files changed, 14 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 71b897a84..85ba4230a 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -908,6 +908,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { break; } + e->Procedure.entry_point_only = ac.entry_point_only; e->Procedure.is_export = ac.is_export; e->deprecated_message = ac.deprecated_message; e->warning_message = ac.warning_message; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 71accfb81..14e3bc0de 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7195,6 +7195,14 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } add_entity_use(c, operand->expr, initial_entity); + + if (initial_entity->Procedure.entry_point_only) { + if (c->curr_proc_decl && c->curr_proc_decl->entity == c->info->entry_point) { + // Okay + } else { + error(operand->expr, "Procedures with the attribute '@(entry_point_only)' can only be called directly from the user-level entry point procedure"); + } + } } if (operand->mode != Addressing_ProcGroup) { diff --git a/src/checker.cpp b/src/checker.cpp index 79328d648..ac885222d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3413,6 +3413,9 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { error(elem, "Expected a string value for '%.*s'", LIT(name)); } return true; + } else if (name == "entry_point_only") { + ac->entry_point_only = true; + return true; } return false; } diff --git a/src/checker.hpp b/src/checker.hpp index a6a5f6788..7c399e50f 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -123,6 +123,7 @@ struct AttributeContext { bool init : 1; bool fini : 1; bool set_cold : 1; + bool entry_point_only : 1; u32 optimization_mode; // ProcedureOptimizationMode i64 foreign_import_priority_index; String extra_linker_flags; diff --git a/src/entity.cpp b/src/entity.cpp index ce27da3f2..d0b3cf139 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -250,6 +250,7 @@ struct Entity { bool is_export : 1; bool generated_from_polymorphic : 1; bool target_feature_disabled : 1; + bool entry_point_only : 1; String target_feature; } Procedure; struct { -- cgit v1.2.3 From d7d23e65eae616d44cc070edff8171eb3160b5b0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Jan 2024 13:47:00 +0000 Subject: Clean up error block usage --- src/build_settings.cpp | 1 + src/check_decl.cpp | 7 +++--- src/check_expr.cpp | 68 +++++++++++++++++++++++++++++--------------------- src/check_stmt.cpp | 6 ++--- src/check_type.cpp | 3 +-- src/checker.cpp | 6 ++--- src/main.cpp | 2 ++ 7 files changed, 50 insertions(+), 43 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d91a31ff2..18ad8ac0d 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -361,6 +361,7 @@ struct BuildContext { bool ignore_warnings; bool warnings_as_errors; bool hide_error_line; + bool terse_errors; bool has_ansi_terminal_colours; bool ignore_lazy; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 85ba4230a..8a3f89877 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -138,11 +138,10 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l } if (o->type && is_type_no_copy(o->type)) { - begin_error_block(); + ERROR_BLOCK(); if (check_no_copy_assignment(*o, str_lit("initialization"))) { error_line("\tInitialization of a #no_copy type must be either implicitly zero, a constant literal, or a return value from a call expression"); } - end_error_block(); } } if (rhs_count > 0 && lhs_count != rhs_count) { @@ -1301,8 +1300,8 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, D continue; } - begin_error_block(); - defer (end_error_block()); + + ERROR_BLOCK(); ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type); bool both_have_where_clauses = false; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 14e3bc0de..8d347bec7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -184,6 +184,8 @@ gb_internal void populate_check_did_you_mean_objc_entity(StringSet *set, Entity gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, char const *prefix = "") { + if (build_context.terse_errors) { return; } + ERROR_BLOCK(); GB_ASSERT(e->kind == Entity_TypeName); GB_ASSERT(e->TypeName.objc_metadata != nullptr); @@ -204,6 +206,8 @@ gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, b } gb_internal void check_did_you_mean_type(String const &name, Array const &fields, char const *prefix = "") { + if (build_context.terse_errors) { return; } + ERROR_BLOCK(); DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name); @@ -217,6 +221,8 @@ gb_internal void check_did_you_mean_type(String const &name, Array con gb_internal void check_did_you_mean_type(String const &name, Slice const &fields, char const *prefix = "") { + if (build_context.terse_errors) { return; } + ERROR_BLOCK(); DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name); @@ -229,6 +235,8 @@ gb_internal void check_did_you_mean_type(String const &name, Slice con } gb_internal void check_did_you_mean_scope(String const &name, Scope *scope, char const *prefix = "") { + if (build_context.terse_errors) { return; } + ERROR_BLOCK(); DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.count, name); @@ -2203,7 +2211,6 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ ERROR_BLOCK(); - if (is_type_numeric(o->type) && is_type_numeric(type)) { if (!is_type_integer(o->type) && is_type_integer(type)) { error(o->expr, "'%s' truncated to '%s', got %s", a, b, s); @@ -2264,8 +2271,7 @@ gb_internal void check_old_for_or_switch_value_usage(Ast *expr) { if (e != nullptr && (e->flags & EntityFlag_OldForOrSwitchValue) != 0) { GB_ASSERT(e->kind == Entity_Variable); - begin_error_block(); - defer (end_error_block()); + ERROR_BLOCK(); if ((e->flags & EntityFlag_ForValue) != 0) { Type *parent_type = type_deref(e->Variable.for_loop_parent_type); @@ -2309,8 +2315,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * break; default: { - begin_error_block(); - defer (end_error_block()); + ERROR_BLOCK(); error(op, "Cannot take the pointer address of '%s'", str); if (e != nullptr && (e->flags & EntityFlag_ForValue) != 0) { Type *parent_type = type_deref(e->Variable.for_loop_parent_type); @@ -3071,7 +3076,7 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { x->mode = Addressing_Invalid; - begin_error_block(); + ERROR_BLOCK(); error(x->expr, "Cannot cast '%s' as '%s' from '%s'", expr_str, to_type, from_type); if (is_const_expr) { gbString val_str = exact_value_to_string(x->value); @@ -3094,8 +3099,6 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { } check_cast_error_suggestion(c, x, type); - end_error_block(); - return; } @@ -4047,8 +4050,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar if (check_is_assignable_to(c, operand, elem)) { if (t->Matrix.row_count != t->Matrix.column_count) { operand->mode = Addressing_Invalid; - begin_error_block(); - defer (end_error_block()); + ERROR_BLOCK(); convert_untyped_error(c, operand, target_type); error_line("\tNote: Only a square matrix types can be initialized with a scalar value\n"); @@ -4109,8 +4111,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar target_type = t->Union.variants[first_success_index]; break; } else if (valid_count > 1) { - begin_error_block(); - defer (end_error_block()); + ERROR_BLOCK(); GB_ASSERT(first_success_index >= 0); operand->mode = Addressing_Invalid; @@ -4136,8 +4137,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar } else if (is_type_untyped_uninit(operand->type)) { target_type = t_untyped_uninit; } else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) { - begin_error_block(); - defer (end_error_block()); + ERROR_BLOCK(); operand->mode = Addressing_Invalid; convert_untyped_error(c, operand, target_type); @@ -4714,6 +4714,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod entity = scope_lookup_current(import_scope, entity_name); bool allow_builtin = false; if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) { + ERROR_BLOCK(); error(node, "'%.*s' is not declared by '%.*s'", LIT(entity_name), LIT(import_name)); operand->mode = Addressing_Invalid; operand->expr = node; @@ -4914,6 +4915,8 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod error(op_expr, "Type '%s' has no field '%s'", op_str, sel_str); } } else { + ERROR_BLOCK(); + error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str); if (operand->type != nullptr && selector->kind == Ast_Ident) { @@ -6338,8 +6341,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, }; if (valids.count == 0) { - begin_error_block(); - defer (end_error_block()); + ERROR_BLOCK(); error(operand->expr, "No procedures or ambiguous call for procedure group '%s' that match with the given arguments", expr_name); if (positional_operands.count == 0 && named_operands.count == 0) { @@ -6429,8 +6431,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, data.result_type = t_invalid; } else if (valids.count > 1) { - begin_error_block(); - defer (end_error_block()); + ERROR_BLOCK(); error(operand->expr, "Ambiguous procedure group call '%s' that match with the given arguments", expr_name); print_argument_types(); @@ -7649,6 +7650,8 @@ gb_internal ExprKind check_implicit_selector_expr(CheckerContext *c, Operand *o, String name = ise->selector->Ident.token.string; if (is_type_enum(th)) { + ERROR_BLOCK(); + Type *bt = base_type(th); GB_ASSERT(bt->kind == Type_Enum); @@ -9050,8 +9053,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } if (unhandled.count > 0) { - begin_error_block(); - defer (end_error_block()); + ERROR_BLOCK(); if (unhandled.count == 1) { error_no_newline(node, "Unhandled enumerated array case: %.*s", LIT(unhandled[0]->token.string)); @@ -9062,9 +9064,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * error_line("\t%.*s\n", LIT(f->token.string)); } } - error_line("\n"); - error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type)); + if (!build_context.terse_errors) { + error_line("\n"); + error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type)); + } } } @@ -9688,7 +9692,9 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, if (index < 0) { gbString str = expr_to_string(o->expr); error(o->expr, "Cannot index a constant '%s'", str); - error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); + if (!build_context.terse_errors) { + error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); + } gb_string_free(str); o->mode = Addressing_Invalid; o->expr = node; @@ -9702,7 +9708,9 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, if (!success) { gbString str = expr_to_string(o->expr); error(o->expr, "Cannot index a constant '%s' with index %lld", str, cast(long long)index); - error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); + if (!build_context.terse_errors) { + error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); + } gb_string_free(str); o->mode = Addressing_Invalid; o->expr = node; @@ -9890,7 +9898,9 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, if (!all_constant) { gbString str = expr_to_string(o->expr); error(o->expr, "Cannot slice '%s' with non-constant indices", str); - error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); + if (!build_context.terse_errors) { + error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); + } gb_string_free(str); o->mode = Addressing_Value; // NOTE(bill): Keep subsequent values going without erring o->expr = node; @@ -10246,15 +10256,15 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast } else { gbString str = expr_to_string(o->expr); gbString typ = type_to_string(o->type); - begin_error_block(); + ERROR_BLOCK(); error(o->expr, "Cannot dereference '%s' of type '%s'", str, typ); if (o->type && is_type_multi_pointer(o->type)) { - error_line("\tDid you mean '%s[0]'?\n", str); + if (!build_context.terse_errors) { + error_line("\tDid you mean '%s[0]'?\n", str); + } } - end_error_block(); - gb_string_free(typ); gb_string_free(str); o->mode = Addressing_Invalid; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index b93be734e..d56e5e212 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1085,8 +1085,7 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags } if (unhandled.count > 0) { - begin_error_block(); - defer (end_error_block()); + ERROR_BLOCK(); if (unhandled.count == 1) { error_no_newline(node, "Unhandled switch case: %.*s", LIT(unhandled[0]->token.string)); @@ -1813,7 +1812,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f } if (new_name_count == 0) { - begin_error_block(); + ERROR_BLOCK(); error(node, "No new declarations on the left hand side"); bool all_underscore = true; for (Ast *name : vd->names) { @@ -1831,7 +1830,6 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f error_line("\tSuggestion: Try changing the declaration (:=) to an assignment (=)\n"); } - end_error_block(); } Type *init_type = nullptr; diff --git a/src/check_type.cpp b/src/check_type.cpp index f11418dc0..a95026711 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2702,14 +2702,13 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T check_expr_or_type(&c, &o, pt->type); if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) { // NOTE(bill): call check_type_expr again to get a consistent error message - begin_error_block(); + ERROR_BLOCK(); elem = check_type_expr(&c, pt->type, nullptr); if (o.mode == Addressing_Variable) { gbString s = expr_to_string(pt->type); error_line("\tSuggestion: ^ is used for pointer types, did you mean '&%s'?\n", s); gb_string_free(s); } - end_error_block(); } else { elem = o.type; } diff --git a/src/checker.cpp b/src/checker.cpp index ac885222d..d25acb15e 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4025,12 +4025,11 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) { if (c->foreign_context.default_cc > 0) { cc = c->foreign_context.default_cc; } else if (is_arch_wasm()) { - begin_error_block(); + ERROR_BLOCK(); error(init, "For wasm related targets, it is required that you either define the" " @(default_calling_convention=) on the foreign block or" " explicitly assign it on the procedure signature"); error_line("\tSuggestion: when dealing with normal Odin code (e.g. js_wasm32), use \"contextless\"; when dealing with Emscripten like code, use \"c\"\n"); - end_error_block(); } } e->Procedure.link_prefix = c->foreign_context.link_prefix; @@ -4077,8 +4076,7 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) { if (e->kind != Entity_Procedure) { if (fl != nullptr) { - begin_error_block(); - defer (end_error_block()); + ERROR_BLOCK(); AstKind kind = init->kind; error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_strings[kind])); diff --git a/src/main.cpp b/src/main.cpp index 4d4e01ada..fd754248b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1160,10 +1160,12 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_TerseErrors: build_context.hide_error_line = true; + build_context.terse_errors = true; break; case BuildFlag_VerboseErrors: gb_printf_err("-verbose-errors is not the default, -terse-errors can now disable it\n"); build_context.hide_error_line = false; + build_context.terse_errors = false; break; case BuildFlag_ErrorPosStyle: -- cgit v1.2.3 From 73f57c5933e4199a239389fb671e1babe7ff6cc4 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 20 Jan 2024 14:27:50 +0100 Subject: Clarify #location error message when not a call. --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8d347bec7..bc7ff1bbb 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7895,7 +7895,7 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A } else { if (name == "location") { init_core_source_code_location(c->checker); - error(node, "'#%.*s' must be used in a call expression", LIT(name)); + error(node, "'#location' must be used as a call, i.e. #location(proc), where #location() defaults to the procedure in which it was used."); o->type = t_source_code_location; o->mode = Addressing_Value; } else if ( -- cgit v1.2.3 From 15b40a4f292ec0fbb71d2a16a0f8b3cd52f41a9e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 26 Jan 2024 12:56:16 +0000 Subject: Fix #3122 --- src/check_expr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index bc7ff1bbb..f8c5540f4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2988,6 +2988,9 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type } // proc <-> proc if (is_type_proc(src) && is_type_proc(dst)) { + if (is_type_polymorphic(src) || is_type_polymorphic(dst)) { + return false; + } return true; } @@ -3067,7 +3070,6 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { bool is_const_expr = x->mode == Addressing_Constant; bool can_convert = check_cast_internal(c, x, type); - if (!can_convert) { TEMPORARY_ALLOCATOR_GUARD(); gbString expr_str = expr_to_string(x->expr, temporary_allocator()); -- cgit v1.2.3 From d04c82e5471bb291cddbef883a36b1caad3b2b99 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 28 Jan 2024 21:20:30 +0000 Subject: Move matrix compiler `builtin`s to `intrinsics`; alias within core_builtin_matrix.odin --- base/runtime/core_builtin_matrix.odin | 9 +++++++++ src/check_expr.cpp | 3 ++- src/checker.cpp | 1 + src/checker_builtin_procs.hpp | 20 ++++++++++---------- 4 files changed, 22 insertions(+), 11 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/base/runtime/core_builtin_matrix.odin b/base/runtime/core_builtin_matrix.odin index 7d60d625c..ed1b5b1e6 100644 --- a/base/runtime/core_builtin_matrix.odin +++ b/base/runtime/core_builtin_matrix.odin @@ -3,6 +3,15 @@ package runtime import "core:intrinsics" _ :: intrinsics +@(builtin) +transpose :: intrinsics.transpose +@(builtin) +outer_product :: intrinsics.outer_product +@(builtin) +hadamard_product :: intrinsics.hadamard_product +@(builtin) +matrix_flatten :: intrinsics.matrix_flatten + @(builtin) determinant :: proc{ diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f8c5540f4..a6081a1cc 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4577,7 +4577,8 @@ gb_internal bool is_entity_declared_for_selector(Entity *entity, Scope *import_s if (entity->kind == Entity_Builtin) { // NOTE(bill): Builtin's are in the universal scope which is part of every scopes hierarchy // This means that we should just ignore the found result through it - *allow_builtin = entity->scope == import_scope || entity->scope != builtin_pkg->scope; + *allow_builtin = entity->scope == import_scope || + (entity->scope != builtin_pkg->scope && entity->scope != intrinsics_pkg->scope); } else if ((entity->scope->flags&ScopeFlag_Global) == ScopeFlag_Global && (import_scope->flags&ScopeFlag_Global) == 0) { is_declared = false; } diff --git a/src/checker.cpp b/src/checker.cpp index 563bb2781..47fcd3d8f 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3835,6 +3835,7 @@ gb_internal void check_builtin_attributes(CheckerContext *ctx, Entity *e, Array< case Entity_ProcGroup: case Entity_Procedure: case Entity_TypeName: + case Entity_Constant: // Okay break; default: diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 3bab16293..42ffa6938 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -34,11 +34,6 @@ enum BuiltinProcId { BuiltinProc_soa_zip, BuiltinProc_soa_unzip, - - BuiltinProc_transpose, - BuiltinProc_outer_product, - BuiltinProc_hadamard_product, - BuiltinProc_matrix_flatten, BuiltinProc_unreachable, @@ -48,6 +43,11 @@ enum BuiltinProcId { // "Intrinsics" BuiltinProc_is_package_imported, + + BuiltinProc_transpose, + BuiltinProc_outer_product, + BuiltinProc_hadamard_product, + BuiltinProc_matrix_flatten, BuiltinProc_soa_struct, @@ -341,11 +341,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("soa_zip"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("soa_unzip"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - - {STR_LIT("transpose"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("outer_product"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("hadamard_product"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, - {STR_LIT("matrix_flatten"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("unreachable"), 0, false, Expr_Expr, BuiltinProcPkg_builtin, /*diverging*/true}, @@ -356,6 +351,11 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { // "Intrinsics" {STR_LIT("is_package_imported"), 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}, + {STR_LIT("matrix_flatten"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("soa_struct"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, // Type -- cgit v1.2.3 From a78f062499c7f0112558872a500904e6fbc6761b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 28 Jan 2024 23:49:59 +0000 Subject: Fix semantics for casting between polymorphic specialized procedures --- src/check_expr.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f8c5540f4..4f47ba523 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2988,7 +2988,11 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type } // proc <-> proc if (is_type_proc(src) && is_type_proc(dst)) { - if (is_type_polymorphic(src) || is_type_polymorphic(dst)) { + if (is_type_polymorphic(dst)) { + if (is_type_polymorphic(src) && + operand->mode == Addressing_Variable) { + return true; + } return false; } return true; -- cgit v1.2.3 From e7122a095045440380e2eed65e9afa90b035c277 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 2 Feb 2024 11:42:22 +0000 Subject: Minimize extra dependencies if u128/i128 and f16 are not used --- src/check_expr.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/checker.cpp | 42 +++++++++++++++++++++--------------------- 2 files changed, 69 insertions(+), 26 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 041bf1703..d7ecbbe8d 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3114,6 +3114,25 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { final_type = default_type(x->type); } update_untyped_expr_type(c, x->expr, final_type, true); + } else { + Type *src = core_type(x->type); + Type *dst = core_type(type); + if (src != dst) { + if (is_type_integer_128bit(src) && is_type_float(dst)) { + add_package_dependency(c, "runtime", "floattidf_unsigned"); + add_package_dependency(c, "runtime", "floattidf"); + } else if (is_type_integer_128bit(dst) && is_type_float(src)) { + add_package_dependency(c, "runtime", "fixunsdfti"); + add_package_dependency(c, "runtime", "fixunsdfdi"); + } else if (src == t_f16 && is_type_float(dst)) { + add_package_dependency(c, "runtime", "gnu_h2f_ieee"); + add_package_dependency(c, "runtime", "extendhfsf2"); + } else if (is_type_float(dst) && dst == t_f16) { + add_package_dependency(c, "runtime", "truncsfhf2"); + add_package_dependency(c, "runtime", "truncdfhf2"); + add_package_dependency(c, "runtime", "gnu_f2h_ieee"); + } + } } x->type = type; @@ -3734,9 +3753,14 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ x->mode = Addressing_Invalid; return; } - - if (op.kind == Token_Quo || op.kind == Token_QuoEq) { - Type *bt = base_type(x->type); + Type *bt = base_type(x->type); + if (op.kind == Token_Mod || op.kind == Token_ModEq || + op.kind == Token_ModMod || op.kind == Token_ModModEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_u128: add_package_dependency(c, "runtime", "umodti3"); break; + case Basic_i128: add_package_dependency(c, "runtime", "modti3"); break; + } + } else if (op.kind == Token_Quo || op.kind == Token_QuoEq) { if (bt->kind == Type_Basic) switch (bt->Basic.kind) { case Basic_complex32: add_package_dependency(c, "runtime", "quo_complex32"); break; case Basic_complex64: add_package_dependency(c, "runtime", "quo_complex64"); break; @@ -3744,13 +3768,32 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ case Basic_quaternion64: add_package_dependency(c, "runtime", "quo_quaternion64"); break; case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break; case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break; + + case Basic_u128: add_package_dependency(c, "runtime", "udivti3"); break; + case Basic_i128: add_package_dependency(c, "runtime", "divti3"); break; } } else if (op.kind == Token_Mul || op.kind == Token_MulEq) { - Type *bt = base_type(x->type); if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break; + case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break; case Basic_quaternion128: add_package_dependency(c, "runtime", "mul_quaternion128"); break; case Basic_quaternion256: add_package_dependency(c, "runtime", "mul_quaternion256"); break; + + + case Basic_u128: + case Basic_i128: + if (is_arch_wasm()) { + add_package_dependency(c, "runtime", "__multi3"); + } + break; + } + } else if (op.kind == Token_Shl || op.kind == Token_ShlEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_u128: + case Basic_i128: + if (is_arch_wasm()) { + add_package_dependency(c, "runtime", "__ashlti3"); + } + break; } } diff --git a/src/checker.cpp b/src/checker.cpp index 8c94ddf86..5e0eaacc7 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2567,27 +2567,27 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("memmove"), ); - FORCE_ADD_RUNTIME_ENTITIES(!build_context.tilde_backend, - // Extended data type internal procedures - str_lit("umodti3"), - str_lit("udivti3"), - str_lit("modti3"), - str_lit("divti3"), - str_lit("fixdfti"), - str_lit("fixunsdfti"), - str_lit("fixunsdfdi"), - str_lit("floattidf"), - str_lit("floattidf_unsigned"), - str_lit("truncsfhf2"), - str_lit("truncdfhf2"), - str_lit("gnu_h2f_ieee"), - str_lit("gnu_f2h_ieee"), - str_lit("extendhfsf2"), - - // WASM Specific - str_lit("__ashlti3"), - str_lit("__multi3"), - ); + // FORCE_ADD_RUNTIME_ENTITIES(!build_context.tilde_backend, + // // Extended data type internal procedures + // str_lit("umodti3"), + // str_lit("udivti3"), + // str_lit("modti3"), + // str_lit("divti3"), + // str_lit("fixdfti"), + // str_lit("fixunsdfti"), + // str_lit("fixunsdfdi"), + // str_lit("floattidf"), + // str_lit("floattidf_unsigned"), + // str_lit("truncsfhf2"), + // str_lit("truncdfhf2"), + // str_lit("gnu_h2f_ieee"), + // str_lit("gnu_f2h_ieee"), + // str_lit("extendhfsf2"), + + // // WASM Specific + // str_lit("__ashlti3"), + // str_lit("__multi3"), + // ); FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_rtti, // Odin types -- cgit v1.2.3 From 19535d872162b7968f10822c658b51069cf81e65 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Feb 2024 11:11:28 +0000 Subject: Add require flags to 128-bit integer procedures --- src/check_expr.cpp | 15 +++++++++------ src/checker.cpp | 5 ++++- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d7ecbbe8d..7049e5974 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3753,12 +3753,15 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ x->mode = Addressing_Invalid; return; } + + bool REQUIRE = true; + Type *bt = base_type(x->type); if (op.kind == Token_Mod || op.kind == Token_ModEq || op.kind == Token_ModMod || op.kind == Token_ModModEq) { if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_u128: add_package_dependency(c, "runtime", "umodti3"); break; - case Basic_i128: add_package_dependency(c, "runtime", "modti3"); break; + case Basic_u128: add_package_dependency(c, "runtime", "umodti3", REQUIRE); break; + case Basic_i128: add_package_dependency(c, "runtime", "modti3", REQUIRE); break; } } else if (op.kind == Token_Quo || op.kind == Token_QuoEq) { if (bt->kind == Type_Basic) switch (bt->Basic.kind) { @@ -3769,8 +3772,8 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break; case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break; - case Basic_u128: add_package_dependency(c, "runtime", "udivti3"); break; - case Basic_i128: add_package_dependency(c, "runtime", "divti3"); break; + case Basic_u128: add_package_dependency(c, "runtime", "udivti3", REQUIRE); break; + case Basic_i128: add_package_dependency(c, "runtime", "divti3", REQUIRE); break; } } else if (op.kind == Token_Mul || op.kind == Token_MulEq) { if (bt->kind == Type_Basic) switch (bt->Basic.kind) { @@ -3782,7 +3785,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ case Basic_u128: case Basic_i128: if (is_arch_wasm()) { - add_package_dependency(c, "runtime", "__multi3"); + add_package_dependency(c, "runtime", "__multi3", REQUIRE); } break; } @@ -3791,7 +3794,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ case Basic_u128: case Basic_i128: if (is_arch_wasm()) { - add_package_dependency(c, "runtime", "__ashlti3"); + add_package_dependency(c, "runtime", "__ashlti3", REQUIRE); } break; } diff --git a/src/checker.cpp b/src/checker.cpp index 5e0eaacc7..4fdcec5f3 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -810,13 +810,16 @@ gb_internal AstPackage *get_core_package(CheckerInfo *info, String name) { return *found; } -gb_internal void add_package_dependency(CheckerContext *c, char const *package_name, char const *name) { +gb_internal void add_package_dependency(CheckerContext *c, char const *package_name, char const *name, bool required=false) { String n = make_string_c(name); AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); Entity *e = scope_lookup(p->scope, n); GB_ASSERT_MSG(e != nullptr, "%s", name); GB_ASSERT(c->decl != nullptr); e->flags |= EntityFlag_Used; + if (required) { + e->flags |= EntityFlag_Require; + } add_dependency(c->info, c->decl, e); } -- cgit v1.2.3 From 27feb5998c5a86ffa5ce661313f8beae585804d8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 5 Feb 2024 13:49:10 +0000 Subject: Add require to 128-bit and f16 casts --- src/check_expr.cpp | 19 ++++++++++--------- src/checker.cpp | 42 +++++++++++++++++++++--------------------- 2 files changed, 31 insertions(+), 30 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7049e5974..9b71208cd 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3118,19 +3118,20 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { Type *src = core_type(x->type); Type *dst = core_type(type); if (src != dst) { + bool const REQUIRE = true; if (is_type_integer_128bit(src) && is_type_float(dst)) { - add_package_dependency(c, "runtime", "floattidf_unsigned"); - add_package_dependency(c, "runtime", "floattidf"); + add_package_dependency(c, "runtime", "floattidf_unsigned", REQUIRE); + add_package_dependency(c, "runtime", "floattidf", REQUIRE); } else if (is_type_integer_128bit(dst) && is_type_float(src)) { - add_package_dependency(c, "runtime", "fixunsdfti"); - add_package_dependency(c, "runtime", "fixunsdfdi"); + add_package_dependency(c, "runtime", "fixunsdfti", REQUIRE); + add_package_dependency(c, "runtime", "fixunsdfdi", REQUIRE); } else if (src == t_f16 && is_type_float(dst)) { - add_package_dependency(c, "runtime", "gnu_h2f_ieee"); - add_package_dependency(c, "runtime", "extendhfsf2"); + add_package_dependency(c, "runtime", "gnu_h2f_ieee", REQUIRE); + add_package_dependency(c, "runtime", "extendhfsf2", REQUIRE); } else if (is_type_float(dst) && dst == t_f16) { - add_package_dependency(c, "runtime", "truncsfhf2"); - add_package_dependency(c, "runtime", "truncdfhf2"); - add_package_dependency(c, "runtime", "gnu_f2h_ieee"); + add_package_dependency(c, "runtime", "truncsfhf2", REQUIRE); + add_package_dependency(c, "runtime", "truncdfhf2", REQUIRE); + add_package_dependency(c, "runtime", "gnu_f2h_ieee", REQUIRE); } } } diff --git a/src/checker.cpp b/src/checker.cpp index 7d8f456df..8f1aa5336 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2570,27 +2570,27 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("memmove"), ); - FORCE_ADD_RUNTIME_ENTITIES(is_arch_wasm() && !build_context.tilde_backend, - // Extended data type internal procedures - str_lit("umodti3"), - str_lit("udivti3"), - str_lit("modti3"), - str_lit("divti3"), - str_lit("fixdfti"), - str_lit("fixunsdfti"), - str_lit("fixunsdfdi"), - str_lit("floattidf"), - str_lit("floattidf_unsigned"), - str_lit("truncsfhf2"), - str_lit("truncdfhf2"), - str_lit("gnu_h2f_ieee"), - str_lit("gnu_f2h_ieee"), - str_lit("extendhfsf2"), - - // WASM Specific - str_lit("__ashlti3"), - str_lit("__multi3"), - ); + // FORCE_ADD_RUNTIME_ENTITIES(is_arch_wasm() && !build_context.tilde_backend, + // // Extended data type internal procedures + // str_lit("umodti3"), + // str_lit("udivti3"), + // str_lit("modti3"), + // str_lit("divti3"), + // str_lit("fixdfti"), + // str_lit("fixunsdfti"), + // str_lit("fixunsdfdi"), + // str_lit("floattidf"), + // str_lit("floattidf_unsigned"), + // str_lit("truncsfhf2"), + // str_lit("truncdfhf2"), + // str_lit("gnu_h2f_ieee"), + // str_lit("gnu_f2h_ieee"), + // str_lit("extendhfsf2"), + + // // WASM Specific + // str_lit("__ashlti3"), + // str_lit("__multi3"), + // ); FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_rtti, // Odin types -- 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_expr.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 fea38f6910f4abb037e2581f28d7592c31991efe Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 14:01:39 +0000 Subject: Minor changes to futex implementation on Linux --- src/check_expr.cpp | 6 ++++-- src/threading.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 11eb4b533..685bcdd6e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1241,7 +1241,7 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T } case Type_Pointer: if (source->kind == Type_Pointer) { - isize level = check_is_assignable_to_using_subtype(source->Pointer.elem, poly->Pointer.elem); + isize level = check_is_assignable_to_using_subtype(source->Pointer.elem, poly->Pointer.elem, /*level*/0, /*src_is_ptr*/false, /*allow_polymorphic*/true); if (level > 0) { return true; } @@ -1413,7 +1413,9 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T return ok; } - // return check_is_assignable_to(c, &o, poly); + + // NOTE(bill): Check for subtypes of + // return check_is_assignable_to(c, &o, poly); // && is_type_subtype_of_and_allow_polymorphic(o.type, poly); } return false; case Type_Tuple: diff --git a/src/threading.cpp b/src/threading.cpp index 725b58c89..684b13bc3 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -656,7 +656,7 @@ gb_internal void futex_wait(Futex *addr, Footex val) { for (;;) { int ret = syscall(SYS_futex, addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, NULL, NULL, 0); if (ret == -1) { - if (errno != EAGAIN) { + if (errno != EAGAIN && errno != EINTR) { perror("Futex wait"); GB_PANIC("Failed in futex wait!\n"); } else { -- cgit v1.2.3 From 5a84a0822596fac47dd35bf1c2f1d9bb60bbe5c1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 17:24:42 +0000 Subject: Add general support for `bit_field`s --- base/runtime/internal.odin | 22 ++++++++++++ core/fmt/fmt.odin | 10 ++++-- src/check_expr.cpp | 86 ++++++++++++++++++++++++++++++++++++++------ src/check_stmt.cpp | 10 ++++++ src/check_type.cpp | 21 +++++++++-- src/checker.hpp | 1 + src/entity.cpp | 2 ++ src/llvm_backend.hpp | 8 +++++ src/llvm_backend_expr.cpp | 16 +++++++++ src/llvm_backend_general.cpp | 51 ++++++++++++++++++++++++-- src/parser.hpp | 1 + src/types.cpp | 34 ++++++++++++++++++ 12 files changed, 245 insertions(+), 17 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/base/runtime/internal.odin b/base/runtime/internal.odin index 691f76ff1..62bee8620 100644 --- a/base/runtime/internal.odin +++ b/base/runtime/internal.odin @@ -1034,3 +1034,25 @@ fixdfti :: proc(a: u64) -> i128 { } } + + + +__write_bits :: proc "contextless" (dst, src: [^]byte, offset: uintptr, size: uintptr) { + for i in 0..value.kind == ExactValue_Integer) { gbString b = type_to_string(type); i64 sz = type_size_of(type); + i64 bit_size = 8*sz; + bool size_changed = false; + if (max_bit_size > 0) { + size_changed = (bit_size != max_bit_size); + bit_size = gb_min(bit_size, max_bit_size); + } BigInt *bi = &o->value.value_integer; if (is_type_unsigned(type)) { if (big_int_is_neg(bi)) { @@ -2083,25 +2089,36 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, } else { BigInt one = big_int_make_u64(1); BigInt max_size = big_int_make_u64(1); - BigInt bits = big_int_make_i64(8*sz); + BigInt bits = big_int_make_i64(bit_size); big_int_shl_eq(&max_size, &bits); big_int_sub_eq(&max_size, &one); String max_size_str = big_int_to_string(temporary_allocator(), &max_size); - error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + + if (size_changed) { + error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %u' is '%.*s'\n", b, bit_size, LIT(max_size_str)); + } else { + error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + } } } else { BigInt zero = big_int_make_u64(0); BigInt one = big_int_make_u64(1); BigInt max_size = big_int_make_u64(1); - BigInt bits = big_int_make_i64(8*sz - 1); + BigInt bits = big_int_make_i64(bit_size - 1); big_int_shl_eq(&max_size, &bits); + + String max_size_str = {}; if (big_int_is_neg(bi)) { big_int_neg(&max_size, &max_size); - String max_size_str = big_int_to_string(temporary_allocator(), &max_size); - error_line("\tThe minimum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + max_size_str = big_int_to_string(temporary_allocator(), &max_size); } else { big_int_sub_eq(&max_size, &one); - String max_size_str = big_int_to_string(temporary_allocator(), &max_size); + max_size_str = big_int_to_string(temporary_allocator(), &max_size); + } + + if (size_changed) { + error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %u' is '%.*s'\n", b, bit_size, LIT(max_size_str)); + } else { error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); } } @@ -2112,7 +2129,7 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, } return false; } -gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type) { +gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type, i64 max_bit_size) { gbString a = expr_to_string(o->expr); gbString b = type_to_string(type); defer( @@ -2143,7 +2160,7 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o error_line("\t whereas slices in general are assumed to be mutable.\n"); } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) { error_line("\tSuggestion: the expression may be casted to %s\n", b); - } else if (check_integer_exceed_suggestion(c, o, type)) { + } else if (check_integer_exceed_suggestion(c, o, type, max_bit_size)) { return; } } @@ -2217,13 +2234,18 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ if (!is_type_integer(o->type) && is_type_integer(type)) { error(o->expr, "'%s' truncated to '%s', got %s", a, b, s); } else { + i64 max_bit_size = 0; + if (ctx->bit_field_bit_size) { + max_bit_size = ctx->bit_field_bit_size; + } + if (are_types_identical(o->type, type)) { error(o->expr, "Numeric value '%s' from '%s' cannot be represented by '%s'", s, a, b); } else { error(o->expr, "Cannot convert numeric value '%s' from '%s' to '%s' from '%s'", s, a, b, c); } - check_assignment_error_suggestion(ctx, o, type); + check_assignment_error_suggestion(ctx, o, type, max_bit_size); } } else { error(o->expr, "Cannot convert '%s' to '%s' from '%s', got %s", a, b, c, s); @@ -2234,6 +2256,11 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ } gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { + if (o->expr && o->expr->kind == Ast_SelectorExpr) { + if (o->expr->SelectorExpr.is_bit_field) { + return true; + } + } if (o->mode == Addressing_OptionalOk) { Ast *expr = unselector_expr(o->expr); if (expr->kind != Ast_TypeAssertion) { @@ -2306,6 +2333,8 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * Entity *e = entity_of_node(ue->expr); if (e != nullptr && (e->flags & EntityFlag_Param) != 0) { error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str); + } else if (e != nullptr && (e->flags & EntityFlag_BitFieldField) != 0) { + error(op, "Cannot take the pointer address of '%s' which is a bit_field's field", str); } else { switch (o->mode) { case Addressing_Constant: @@ -5067,6 +5096,11 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod operand->type = entity->type; operand->expr = node; + if (entity->flags & EntityFlag_BitFieldField) { + add_package_dependency(c, "runtime", "__write_bits"); + add_package_dependency(c, "runtime", "__read_bits"); + } + switch (entity->kind) { case Entity_Constant: operand->value = entity->Constant.value; @@ -5080,6 +5114,9 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } break; case Entity_Variable: + if (sel.is_bit_field) { + se->is_bit_field = true; + } if (sel.indirect) { operand->mode = Addressing_Variable; } else if (operand->mode == Addressing_Context) { @@ -11115,6 +11152,33 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; + case_ast_node(f, BitFieldField, node); + str = write_expr_to_string(str, f->name, shorthand); + str = gb_string_appendc(str, ": "); + str = write_expr_to_string(str, f->type, shorthand); + str = gb_string_appendc(str, " | "); + str = write_expr_to_string(str, f->bit_size, shorthand); + case_end; + case_ast_node(bf, BitFieldType, node); + str = gb_string_appendc(str, "bit_field "); + if (!shorthand) { + str = write_expr_to_string(str, bf->backing_type, shorthand); + } + str = gb_string_appendc(str, " {"); + if (shorthand) { + str = gb_string_appendc(str, "..."); + } else { + for_array(i, bf->fields) { + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = write_expr_to_string(str, bf->fields[i], false); + } + return str; + } + str = gb_string_appendc(str, "}"); + case_end; + case_ast_node(ia, InlineAsmExpr, node); str = gb_string_appendc(str, "asm("); for_array(i, ia->param_types) { diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 6897701d6..a7dd9743b 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -485,7 +485,17 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O } } + Entity *lhs_e = entity_of_node(lhs->expr); + u8 prev_bit_field_bit_size = ctx->bit_field_bit_size; + if (lhs_e && lhs_e->kind == Entity_Variable && lhs_e->Variable.bit_field_bit_size) { + // HACK NOTE(bill): This is a bit of a hack, but it will work fine for this use case + ctx->bit_field_bit_size = lhs_e->Variable.bit_field_bit_size; + } + check_assignment(ctx, rhs, assignment_type, str_lit("assignment")); + + ctx->bit_field_bit_size = prev_bit_field_bit_size; + if (rhs->mode == Addressing_Invalid) { return nullptr; } diff --git a/src/check_type.cpp b/src/check_type.cpp index 8afac2fc5..8c746a2f7 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1035,11 +1035,19 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, error(f->bit_size, "A bit_field's specified bit size cannot exceed 64 bits, got %lld", cast(long long)bit_size_i64); bit_size_i64 = 64; } + i64 sz = 8*type_size_of(type); + if (bit_size_i64 > sz) { + error(f->bit_size, "A bit_field's specified bit size cannot exceed its type, got %lld, expect <=%lld", cast(long long)bit_size_i64, cast(long long)sz); + bit_size_i64 = sz; + } + bit_size_u8 = cast(u8)bit_size_i64; Entity *e = alloc_entity_field(ctx->scope, f->name->Ident.token, type, false, field_src_index); e->Variable.docs = docs; e->Variable.comment = comment; + e->Variable.bit_field_bit_size = bit_size_u8; + e->flags |= EntityFlag_BitFieldField; add_entity(ctx, ctx->scope, nullptr, e); array_add(&fields, e); @@ -1050,6 +1058,14 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, GB_ASSERT(fields.count <= bf->fields.count); + auto bit_offsets = slice_make(permanent_allocator(), fields.count); + i64 curr_offset = 0; + for_array(i, bit_sizes) { + bit_offsets[i] = curr_offset; + curr_offset += cast(i64)bit_sizes[i]; + } + + if (total_bit_size > maximum_bit_size) { gbString s = type_to_string(backing_type); error(node, "The numbers required %llu exceeds the backing type's (%s) bit size %llu", @@ -1059,8 +1075,9 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, gb_string_free(s); } - bit_field_type->BitField.fields = slice_from_array(fields); - bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes); + bit_field_type->BitField.fields = slice_from_array(fields); + bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes); + bit_field_type->BitField.bit_offsets = bit_offsets; } gb_internal bool is_type_valid_bit_set_range(Type *t) { diff --git a/src/checker.hpp b/src/checker.hpp index 9aee82257..066d6bb4a 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -475,6 +475,7 @@ struct CheckerContext { bool hide_polymorphic_errors; bool in_polymorphic_specialization; bool allow_arrow_right_selector_expr; + u8 bit_field_bit_size; Scope * polymorphic_scope; Ast *assignment_lhs_hint; diff --git a/src/entity.cpp b/src/entity.cpp index e6c46d37e..916c2b2bd 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -43,6 +43,7 @@ enum EntityFlag : u64 { EntityFlag_NoAlias = 1ull<<9, EntityFlag_TypeField = 1ull<<10, EntityFlag_Value = 1ull<<11, + EntityFlag_BitFieldField = 1ull<<12, @@ -212,6 +213,7 @@ struct Entity { Ast *init_expr; // only used for some variables within procedure bodies i32 field_index; i32 field_group_index; + u8 bit_field_bit_size; ParameterValue param_value; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 026454c81..00d1b7a21 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -84,6 +84,8 @@ enum lbAddrKind { lbAddr_Swizzle, lbAddr_SwizzleLarge, + + lbAddr_BitField, }; struct lbAddr { @@ -118,6 +120,12 @@ struct lbAddr { Type *type; Slice indices; } swizzle_large; + struct { + Type *type; + i64 index; + i64 bit_offset; + i64 bit_size; + } bitfield; }; }; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 0c06c8c1b..6bef21822 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4627,6 +4627,22 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { Selection sel = lookup_field(type, selector, false); GB_ASSERT(sel.entity != nullptr); + if (sel.is_bit_field) { + lbAddr addr = lb_build_addr(p, se->expr); + Type *bf_type = base_type(type_deref(lb_addr_type(addr))); + GB_ASSERT(bf_type->kind == Type_BitField); + + lbValue a = lb_addr_get_ptr(p, addr); + Selection sub_sel = sel; + sub_sel.index.count -= 1; + i32 index = sel.index[sel.index.count-1]; + + Entity *f = bf_type->BitField.fields[index]; + u8 bit_size = bf_type->BitField.bit_sizes[index]; + i64 bit_offset = bf_type->BitField.bit_offsets[index]; + + return lb_addr_bit_field(a, f->type, index, bit_offset, bit_size); + } if (sel.pseudo_field) { GB_ASSERT(sel.entity->kind == Entity_Procedure || sel.entity->kind == Entity_ProcGroup); Entity *e = entity_of_node(sel_node); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 2102420f8..4ff8482a7 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -451,6 +451,20 @@ gb_internal lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slice(temporary_allocator(), 4); + args[0] = dst; + args[1] = lb_address_from_load_or_generate_local(p, value); + args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset); + args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size); + lb_emit_runtime_call(p, "__write_bits", args); + return; + } else if (addr.kind == lbAddr_RelativePointer) { Type *rel_ptr = base_type(lb_addr_type(addr)); GB_ASSERT(rel_ptr->kind == Type_RelativePointer || rel_ptr->kind == Type_RelativeMultiPointer); @@ -1074,8 +1098,31 @@ gb_internal lbValue lb_emit_load(lbProcedure *p, lbValue value) { gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { GB_ASSERT(addr.addr.value != nullptr); + if (addr.kind == lbAddr_BitField) { + lbAddr dst = lb_add_local_generated(p, addr.bitfield.type, true); + lbValue src = addr.addr; - if (addr.kind == lbAddr_RelativePointer) { + auto args = array_make(temporary_allocator(), 4); + args[0] = dst.addr; + args[1] = src; + args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset); + args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size); + lb_emit_runtime_call(p, "__read_bits", args); + + lbValue r = lb_addr_load(p, dst); + + if (!is_type_unsigned(core_type(addr.bitfield.type))) { + // Sign extension + // m := 1<<(bit_size-1) + // r = (r XOR m) - m + Type *t = addr.bitfield.type; + lbValue m = lb_const_int(p->module, t, 1ull<<(addr.bitfield.bit_size-1)); + r = lb_emit_arith(p, Token_Xor, r, m, t); + r = lb_emit_arith(p, Token_Sub, r, m, t); + } + + return r; + } else if (addr.kind == lbAddr_RelativePointer) { Type *rel_ptr = base_type(lb_addr_type(addr)); Type *base_integer = nullptr; Type *pointer_type = nullptr; diff --git a/src/parser.hpp b/src/parser.hpp index ff77c88c7..1f4ec8726 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -429,6 +429,7 @@ AST_KIND(_ExprBegin, "", bool) \ Ast *expr, *selector; \ u8 swizzle_count; /*maximum of 4 components, if set, count >= 2*/ \ u8 swizzle_indices; /*2 bits per component*/ \ + bool is_bit_field; \ }) \ AST_KIND(ImplicitSelectorExpr, "implicit selector expression", struct { Token token; Ast *selector; }) \ AST_KIND(SelectorCallExpr, "selector call expression", struct { \ diff --git a/src/types.cpp b/src/types.cpp index 1c28e6583..be4b8944b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -287,6 +287,7 @@ struct TypeProc { Type * backing_type; \ Slice fields; \ Slice bit_sizes; \ + Slice bit_offsets; \ Ast * node; \ }) \ TYPE_KIND(SoaPointer, struct { Type *elem; }) @@ -408,6 +409,7 @@ struct Selection { bool indirect; // Set if there was a pointer deref anywhere down the line u8 swizzle_count; // maximum components = 4 u8 swizzle_indices; // 2 bits per component, representing which swizzle index + bool is_bit_field; bool pseudo_field; }; gb_global Selection const empty_selection = {0}; @@ -3187,6 +3189,21 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name else if (field_name == "a") mapped_field_name = str_lit("w"); return lookup_field_with_selection(type, mapped_field_name, is_type, sel, allow_blank_ident); } + } else if (type->kind == Type_BitField) { + for_array(i, type->BitField.fields) { + Entity *f = type->BitField.fields[i]; + if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) { + continue; + } + String str = f->token.string; + if (field_name == str) { + selection_add_index(&sel, i); // HACK(bill): Leaky memory + sel.entity = f; + sel.is_bit_field = true; + return sel; + } + } + } else if (type->kind == Type_Basic) { switch (type->Basic.kind) { case Basic_any: { @@ -4551,6 +4568,23 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_appendc(str, gb_bprintf("matrix[%d, %d]", cast(int)type->Matrix.row_count, cast(int)type->Matrix.column_count)); str = write_type_to_string(str, type->Matrix.elem); break; + + case Type_BitField: + str = gb_string_appendc(str, "bit_field "); + str = write_type_to_string(str, type->BitField.backing_type); + str = gb_string_appendc(str, " {"); + for (isize i = 0; i < type->BitField.fields.count; i++) { + Entity *f = type->BitField.fields[i]; + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = gb_string_append_length(str, f->token.string.text, f->token.string.len); + str = gb_string_appendc(str, ": "); + str = write_type_to_string(str, f->type); + str = gb_string_append_fmt(str, " | %u", type->BitField.bit_sizes[i]); + } + str = gb_string_appendc(str, " }"); + break; } return str; -- cgit v1.2.3 From dcbcf75269a75a9d677104f40dd99d3610e1353d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 17:37:42 +0000 Subject: Add doc-format support for `bit_field` --- core/odin/doc-format/doc_format.odin | 8 ++++++-- src/check_expr.cpp | 1 - src/docs_format.cpp | 9 ++++++--- src/docs_writer.cpp | 24 +++++++++++++++++++++++- 4 files changed, 35 insertions(+), 7 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index d22dafd27..360ba0d85 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -10,8 +10,8 @@ Array :: struct($T: typeid) { String :: distinct Array(byte) Version_Type_Major :: 0 -Version_Type_Minor :: 2 -Version_Type_Patch :: 4 +Version_Type_Minor :: 3 +Version_Type_Patch :: 0 Version_Type :: struct { major, minor, patch: u8, @@ -110,6 +110,8 @@ Entity_Flag :: enum u32le { Param_No_Alias = 7, // #no_alias Param_Any_Int = 8, // #any_int + Bit_Field_Field = 19, + Type_Alias = 20, Builtin_Pkg_Builtin = 30, @@ -137,6 +139,7 @@ Entity :: struct { // May be used by (Struct fields and procedure fields): // .Variable // .Constant + // This is equal to the "bit size" it this is a `bit_field`s field field_group_index: i32le, // May used by: @@ -187,6 +190,7 @@ Type_Kind :: enum u32le { Multi_Pointer = 22, Matrix = 23, Soa_Pointer = 24, + Bit_Field = 25, } Type_Elems_Cap :: 4 diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9b15ae3b2..aba2f5831 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -11174,7 +11174,6 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan } str = write_expr_to_string(str, bf->fields[i], false); } - return str; } str = gb_string_appendc(str, "}"); case_end; diff --git a/src/docs_format.cpp b/src/docs_format.cpp index d0bca214b..779190e62 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -14,8 +14,8 @@ struct OdinDocVersionType { }; #define OdinDocVersionType_Major 0 -#define OdinDocVersionType_Minor 2 -#define OdinDocVersionType_Patch 4 +#define OdinDocVersionType_Minor 3 +#define OdinDocVersionType_Patch 0 struct OdinDocHeaderBase { u8 magic[8]; @@ -84,6 +84,7 @@ enum OdinDocTypeKind : u32 { OdinDocType_MultiPointer = 22, OdinDocType_Matrix = 23, OdinDocType_SoaPointer = 24, + OdinDocType_BitField = 25, }; enum OdinDocTypeFlag_Basic : u32 { @@ -170,6 +171,8 @@ enum OdinDocEntityFlag : u64 { OdinDocEntityFlag_Param_NoAlias = 1ull<<7, OdinDocEntityFlag_Param_AnyInt = 1ull<<8, + OdinDocEntityFlag_BitField_Field = 1ull<<19, + OdinDocEntityFlag_Type_Alias = 1ull<<20, OdinDocEntityFlag_Builtin_Pkg_Builtin = 1ull<<30, @@ -192,7 +195,7 @@ struct OdinDocEntity { u32 reserved_for_init; OdinDocString comment; // line comment OdinDocString docs; // preceding comment - i32 field_group_index; + i32 field_group_index; // For `bit_field`s this is the "bit_size" OdinDocEntityIndex foreign_library; OdinDocString link_name; OdinDocArray attributes; diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 6816ae8eb..88d9df40c 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -615,6 +615,19 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { doc_type.types = odin_write_slice(w, types, gb_count_of(types)); } break; + case Type_BitField: + doc_type.kind = OdinDocType_BitField; + { + auto fields = array_make(heap_allocator(), type->BitField.fields.count); + defer (array_free(&fields)); + + for_array(i, type->BitField.fields) { + fields[i] = odin_doc_add_entity(w, type->BitField.fields[i]); + } + doc_type.entities = odin_write_slice(w, fields.data, fields.count); + } + break; + case Type_Struct: doc_type.kind = OdinDocType_Struct; if (type->Struct.soa_kind != StructSoa_None) { @@ -863,6 +876,10 @@ gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) } break; case Entity_Variable: + if (e->flags & EntityFlag_BitFieldField) { + flags |= OdinDocEntityFlag_BitField_Field; + } + if (e->Variable.is_foreign) { flags |= OdinDocEntityFlag_Foreign; } if (e->Variable.is_export) { flags |= OdinDocEntityFlag_Export; } if (e->Variable.thread_local_model != "") { @@ -873,7 +890,12 @@ gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) if (init_expr == nullptr) { init_expr = e->Variable.init_expr; } - field_group_index = e->Variable.field_group_index; + + if (e->flags & EntityFlag_BitFieldField) { + field_group_index = cast(i32)e->Variable.bit_field_bit_size; + } else { + field_group_index = e->Variable.field_group_index; + } break; case Entity_Constant: field_group_index = e->Constant.field_group_index; -- cgit v1.2.3 From 5f001f6d5138d61fbb4900c951e2ccb12894d5ed Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 18:15:13 +0000 Subject: Allow casting between a `bit_field` and its backing type --- src/check_decl.cpp | 1 + src/check_expr.cpp | 7 +++++++ src/llvm_backend_expr.cpp | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 3ccf1b97a..2c0f7a7b8 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -210,6 +210,7 @@ gb_internal bool is_type_distinct(Ast *node) { case Ast_UnionType: case Ast_EnumType: case Ast_ProcType: + case Ast_BitFieldType: return true; case Ast_PointerType: diff --git a/src/check_expr.cpp b/src/check_expr.cpp index aba2f5831..792e5b43c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2908,6 +2908,13 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type } } + if (is_type_bit_field(src)) { + return are_types_identical(core_type(src->BitField.backing_type), dst); + } + if (is_type_bit_field(dst)) { + return are_types_identical(src, core_type(dst->BitField.backing_type)); + } + if (is_type_integer(src) && is_type_rune(dst)) { return true; } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 6bef21822..7b31ca989 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1946,6 +1946,24 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } } + // bit_field <-> backing type + if (is_type_bit_field(src)) { + if (are_types_identical(src->BitField.backing_type, dst)) { + lbValue res = {}; + res.type = t; + res.value = value.value; + return res; + } + } + if (is_type_bit_field(dst)) { + if (are_types_identical(src, dst->BitField.backing_type)) { + lbValue res = {}; + res.type = t; + res.value = value.value; + return res; + } + } + // Pointer <-> uintptr if (is_type_pointer(src) && is_type_uintptr(dst)) { -- cgit v1.2.3 From afcc2889ecf532e03878825d7eb713674d1e7af7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 18:41:15 +0000 Subject: Support compound literals for `bit_field` --- core/odin/doc-format/doc_format.odin | 2 +- src/check_expr.cpp | 49 ++++++++++++++++++++++++++++++++---- src/llvm_backend_expr.cpp | 32 +++++++++++++++++++++++ 3 files changed, 77 insertions(+), 6 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index ebc05c4dc..5636b1059 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -139,7 +139,7 @@ Entity :: struct { // May be used by (Struct fields and procedure fields): // .Variable // .Constant - // This is equal to the "bit size" it this is a `bit_field`s field + // This is equal to the negative of the "bit size" it this is a `bit_field`s field field_group_index: i32le, // May used by: diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 792e5b43c..d5890b191 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8440,6 +8440,11 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice fields_visited_through_raw_union = {}; defer (string_map_destroy(&fields_visited_through_raw_union)); + String assignment_str = str_lit("structure literal"); + if (bt->kind == Type_BitField) { + assignment_str = str_lit("bit_field literal"); + } + for (Ast *elem : elems) { if (elem->kind != Ast_FieldValue) { error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); @@ -8461,17 +8466,26 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, SliceStruct.fields[sel.index[0]]; + Entity *field = nullptr; + if (bt->kind == Type_Struct) { + field = bt->Struct.fields[sel.index[0]]; + } else if (bt->kind == Type_BitField) { + field = bt->BitField.fields[sel.index[0]]; + } else { + GB_PANIC("Unknown type"); + } + + add_entity_use(c, fv->field, field); if (string_set_update(&fields_visited, name)) { if (sel.index.count > 1) { if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found)); } else { - error(fv->field, "Duplicate or reused field '%.*s' in structure literal", LIT(sel.entity->token.string)); + error(fv->field, "Duplicate or reused field '%.*s' in %.*s", LIT(sel.entity->token.string), LIT(assignment_str)); } } else { - error(fv->field, "Duplicate field '%.*s' in structure literal", LIT(field->token.string)); + error(fv->field, "Duplicate field '%.*s' in %.*s", LIT(field->token.string), LIT(assignment_str)); } continue; } else if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { @@ -8479,11 +8493,13 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slicefield, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a structure literal", cast(int)sel.index.count-1, LIT(name)); + error(fv->field, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a %.*s", cast(int)sel.index.count-1, LIT(name), LIT(assignment_str)); continue; } if (sel.index.count > 1) { + GB_ASSERT(bt->kind == Type_Struct); + if (is_constant) { Type *ft = type; for (i32 index : sel.index) { @@ -8544,7 +8560,15 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slicetype, str_lit("structure literal")); + u8 prev_bit_field_bit_size = c->bit_field_bit_size; + if (field->kind == Entity_Variable && field->Variable.bit_field_bit_size) { + // HACK NOTE(bill): This is a bit of a hack, but it will work fine for this use case + c->bit_field_bit_size = field->Variable.bit_field_bit_size; + } + + check_assignment(c, &o, field->type, assignment_str); + + c->bit_field_bit_size = prev_bit_field_bit_size; } } @@ -9346,6 +9370,21 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } break; } + case Type_BitField: { + if (cl->elems.count == 0) { + break; // NOTE(bill): No need to init + } + is_constant = false; + if (cl->elems[0]->kind != Ast_FieldValue) { + gbString type_str = type_to_string(type); + error(node, "%s ('bit_field') compound literals are only allowed to contain 'field = value' elements", type_str); + gb_string_free(type_str); + } else { + check_compound_literal_field_values(c, cl->elems, o, type, is_constant); + } + break; + } + default: { if (cl->elems.count == 0) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 7b31ca989..7e000c9e8 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4235,6 +4235,38 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { switch (bt->kind) { default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; + case Type_BitField: + for (Ast *elem : cl->elems) { + ast_node(fv, FieldValue, elem); + String name = fv->field->Ident.token.string; + Selection sel = lookup_field(bt, name, false); + GB_ASSERT(sel.is_bit_field); + GB_ASSERT(!sel.indirect); + GB_ASSERT(sel.index.count == 1); + GB_ASSERT(sel.entity != nullptr); + + i64 index = sel.index[0]; + i64 bit_offset = 0; + i64 bit_size = -1; + for_array(i, bt->BitField.fields) { + Entity *f = bt->BitField.fields[i]; + if (f == sel.entity) { + bit_offset = bt->BitField.bit_offsets[i]; + bit_size = bt->BitField.bit_sizes[i]; + break; + } + } + GB_ASSERT(bit_size > 0); + + Type *field_type = sel.entity->type; + lbValue field_expr = lb_build_expr(p, fv->value); + field_expr = lb_emit_conv(p, field_expr, field_type); + + lbAddr field_addr = lb_addr_bit_field(v.addr, field_type, index, bit_offset, bit_size); + lb_addr_store(p, field_addr, field_expr); + } + return v; + case Type_Struct: { // TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment. // NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR -- cgit v1.2.3 From fd987b29ff670e6dd7c33c1682927f7bc9c47ef6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 18:47:43 +0000 Subject: Improve error handling with assignments to `bit_field` using constants --- src/check_expr.cpp | 48 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d5890b191..3a8cdf0b1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1886,33 +1886,55 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i BigInt i = v.value_integer; - i64 bit_size = type_size_of(type); + i64 byte_size = type_size_of(type); BigInt umax = {}; BigInt imin = {}; BigInt imax = {}; - if (bit_size < 16) { - big_int_from_u64(&umax, unsigned_integer_maxs[bit_size]); - big_int_from_i64(&imin, signed_integer_mins[bit_size]); - big_int_from_i64(&imax, signed_integer_maxs[bit_size]); - } else { + if (c->bit_field_bit_size > 0) { + i64 bit_size = gb_min(cast(i64)(8*byte_size), cast(i64)c->bit_field_bit_size); + big_int_from_u64(&umax, 1); big_int_from_i64(&imin, 1); big_int_from_i64(&imax, 1); - BigInt bi128 = {}; - BigInt bi127 = {}; - big_int_from_i64(&bi128, 128); - big_int_from_i64(&bi127, 127); + BigInt bu = {}; + BigInt bi = {}; + big_int_from_i64(&bu, bit_size); + big_int_from_i64(&bi, bit_size-1); - big_int_shl_eq(&umax, &bi128); + big_int_shl_eq(&umax, &bu); mp_decr(&umax); - big_int_shl_eq(&imin, &bi127); + big_int_shl_eq(&imin, &bi); big_int_neg(&imin, &imin); - big_int_shl_eq(&imax, &bi127); + big_int_shl_eq(&imax, &bi); mp_decr(&imax); + } else { + if (byte_size < 16) { + big_int_from_u64(&umax, unsigned_integer_maxs[byte_size]); + big_int_from_i64(&imin, signed_integer_mins[byte_size]); + big_int_from_i64(&imax, signed_integer_maxs[byte_size]); + } else { + big_int_from_u64(&umax, 1); + big_int_from_i64(&imin, 1); + big_int_from_i64(&imax, 1); + + BigInt bi128 = {}; + BigInt bi127 = {}; + big_int_from_i64(&bi128, 128); + big_int_from_i64(&bi127, 127); + + big_int_shl_eq(&umax, &bi128); + mp_decr(&umax); + + big_int_shl_eq(&imin, &bi127); + big_int_neg(&imin, &imin); + + big_int_shl_eq(&imax, &bi127); + mp_decr(&imax); + } } switch (type->Basic.kind) { -- cgit v1.2.3 From c7c68520577133d6332bd6df98c44e751b571c03 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 12 Mar 2024 12:11:48 +0000 Subject: Support swizzle selector syntax `.xyzw` for `#simd` vectors --- src/check_expr.cpp | 13 +++++--- src/llvm_backend_expr.cpp | 4 +-- src/llvm_backend_general.cpp | 26 +++++++++++++++- src/types.cpp | 71 ++++++++++++++++++++++++++++---------------- 4 files changed, 82 insertions(+), 32 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3a8cdf0b1..0911e48cf 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4920,7 +4920,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } } - if (entity == nullptr && selector->kind == Ast_Ident && is_type_array(type_deref(operand->type))) { + if (entity == nullptr && selector->kind == Ast_Ident && (is_type_array(type_deref(operand->type)) || is_type_simd_vector(type_deref(operand->type)))) { String field_name = selector->Ident.token.string; if (1 < field_name.len && field_name.len <= 4) { u8 swizzles_xyzw[4] = {'x', 'y', 'z', 'w'}; @@ -4975,8 +4975,10 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod Type *original_type = operand->type; Type *array_type = base_type(type_deref(original_type)); - GB_ASSERT(array_type->kind == Type_Array); - i64 array_count = array_type->Array.count; + GB_ASSERT(array_type->kind == Type_Array || array_type->kind == Type_SimdVector); + + i64 array_count = get_array_type_count(array_type); + for (u8 i = 0; i < index_count; i++) { u8 idx = indices>>(i*2) & 3; if (idx >= array_count) { @@ -4996,7 +4998,6 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod se->swizzle_count = index_count; se->swizzle_indices = indices; - AddressingMode prev_mode = operand->mode; operand->mode = Addressing_SwizzleValue; operand->type = determine_swizzle_array_type(original_type, type_hint, index_count); @@ -5010,6 +5011,10 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod break; } + if (array_type->kind == Type_SimdVector) { + operand->mode = Addressing_Value; + } + Entity *swizzle_entity = alloc_entity_variable(nullptr, make_token_ident(field_name), operand->type, EntityState_Resolved); add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); return swizzle_entity; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 5bc961af2..98618798b 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4655,7 +4655,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { if (se->swizzle_count > 0) { Type *array_type = base_type(type_deref(tav.type)); - GB_ASSERT(array_type->kind == Type_Array); + GB_ASSERT(array_type->kind == Type_Array || array_type->kind == Type_SimdVector); u8 swizzle_count = se->swizzle_count; u8 swizzle_indices_raw = se->swizzle_indices; u8 swizzle_indices[4] = {}; @@ -4671,7 +4671,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { a = lb_addr_get_ptr(p, addr); } - GB_ASSERT(is_type_array(expr->tav.type)); + GB_ASSERT(is_type_array(expr->tav.type) || is_type_simd_vector(expr->tav.type)); return lb_addr_swizzle(a, expr->tav.type, swizzle_count, swizzle_indices); } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 4ff8482a7..09de90dc9 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -434,7 +434,7 @@ gb_internal lbAddr lb_addr_soa_variable(lbValue addr, lbValue index, Ast *index_ } gb_internal lbAddr lb_addr_swizzle(lbValue addr, Type *array_type, u8 swizzle_count, u8 swizzle_indices[4]) { - GB_ASSERT(is_type_array(array_type)); + GB_ASSERT(is_type_array(array_type) || is_type_simd_vector(array_type)); GB_ASSERT(1 < swizzle_count && swizzle_count <= 4); lbAddr v = {lbAddr_Swizzle, addr}; v.swizzle.type = array_type; @@ -1264,6 +1264,30 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { return lb_addr_load(p, res); } else if (addr.kind == lbAddr_Swizzle) { Type *array_type = base_type(addr.swizzle.type); + if (array_type->kind == Type_SimdVector) { + lbValue vec = lb_emit_load(p, addr.addr); + u8 index_count = addr.swizzle.count; + if (index_count == 0) { + return vec; + } + + unsigned mask_len = cast(unsigned)index_count; + LLVMValueRef *mask_elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, index_count); + for (isize i = 0; i < index_count; i++) { + mask_elems[i] = LLVMConstInt(lb_type(p->module, t_u32), addr.swizzle.indices[i], false); + } + + LLVMValueRef mask = LLVMConstVector(mask_elems, mask_len); + + LLVMValueRef v1 = vec.value; + LLVMValueRef v2 = vec.value; + + lbValue res = {}; + res.type = addr.swizzle.type; + res.value = LLVMBuildShuffleVector(p->builder, v1, v2, mask, ""); + return res; + } + GB_ASSERT(array_type->kind == Type_Array); unsigned res_align = cast(unsigned)type_align_of(addr.swizzle.type); diff --git a/src/types.cpp b/src/types.cpp index e9e91dcd4..5a3ad5d6b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3430,31 +3430,6 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name } return sel; - } else if (type->kind == Type_Array) { - if (type->Array.count <= 4) { - // HACK(bill): Memory leak - switch (type->Array.count) { - #define _ARRAY_FIELD_CASE_IF(_length, _name) \ - if (field_name == (_name)) { \ - selection_add_index(&sel, (_length)-1); \ - sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \ - return sel; \ - } - #define _ARRAY_FIELD_CASE(_length, _name0, _name1) \ - case (_length): \ - _ARRAY_FIELD_CASE_IF(_length, _name0); \ - _ARRAY_FIELD_CASE_IF(_length, _name1); \ - /*fallthrough*/ - - _ARRAY_FIELD_CASE(4, "w", "a"); - _ARRAY_FIELD_CASE(3, "z", "b"); - _ARRAY_FIELD_CASE(2, "y", "g"); - _ARRAY_FIELD_CASE(1, "x", "r"); - default: break; - - #undef _ARRAY_FIELD_CASE - } - } } else if (type->kind == Type_DynamicArray) { GB_ASSERT(t_allocator != nullptr); String allocator_str = str_lit("allocator"); @@ -3475,7 +3450,53 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name sel.entity = entity__allocator; return sel; } + + +#define _ARRAY_FIELD_CASE_IF(_length, _name) \ + if (field_name == (_name)) { \ + selection_add_index(&sel, (_length)-1); \ + sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), elem, (_length)-1); \ + return sel; \ } +#define _ARRAY_FIELD_CASE(_length, _name0, _name1) \ +case (_length): \ + _ARRAY_FIELD_CASE_IF(_length, _name0); \ + _ARRAY_FIELD_CASE_IF(_length, _name1); \ + /*fallthrough*/ + + + } else if (type->kind == Type_Array) { + + Type *elem = type->Array.elem; + + if (type->Array.count <= 4) { + // HACK(bill): Memory leak + switch (type->Array.count) { + + _ARRAY_FIELD_CASE(4, "w", "a"); + _ARRAY_FIELD_CASE(3, "z", "b"); + _ARRAY_FIELD_CASE(2, "y", "g"); + _ARRAY_FIELD_CASE(1, "x", "r"); + default: break; + } + } + } else if (type->kind == Type_SimdVector) { + + Type *elem = type->SimdVector.elem; + if (type->SimdVector.count <= 4) { + // HACK(bill): Memory leak + switch (type->SimdVector.count) { + _ARRAY_FIELD_CASE(4, "w", "a"); + _ARRAY_FIELD_CASE(3, "z", "b"); + _ARRAY_FIELD_CASE(2, "y", "g"); + _ARRAY_FIELD_CASE(1, "x", "r"); + default: break; + } + } + } + +#undef _ARRAY_FIELD_CASE +#undef _ARRAY_FIELD_CASE return sel; } -- cgit v1.2.3 From f7ec628cb20375645f99a851d55e031c76688724 Mon Sep 17 00:00:00 2001 From: rick-masters Date: Tue, 12 Mar 2024 23:57:13 +0000 Subject: Fix check for too many arguments to a polymorphic record type. --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 0911e48cf..c5517ffa3 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6847,7 +6847,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O Array ordered_operands = operands; if (!named_fields) { - ordered_operands = array_make(permanent_allocator(), param_count); + ordered_operands = array_make(permanent_allocator(), operands.count); array_copy(&ordered_operands, operands, 0); } else { TEMPORARY_ALLOCATOR_GUARD(); -- cgit v1.2.3 From 7bc962b852e9e4ad0a8619f7265192f528cbe0be Mon Sep 17 00:00:00 2001 From: rick-masters Date: Tue, 12 Mar 2024 23:58:20 +0000 Subject: Fix variable used to index polymorphic parameter. --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c5517ffa3..1e4c7499b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6796,7 +6796,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O isize index = lookup_polymorphic_record_parameter(original_type, name); if (index >= 0) { TypeTuple *params = get_record_polymorphic_params(original_type); - Entity *e = params->variables[i]; + Entity *e = params->variables[index]; if (e->kind == Entity_Constant) { check_expr_with_type_hint(c, &operands[i], fv->value, e->type); continue; -- cgit v1.2.3 From 3875fb08e839d45d2c855115008857b3134f8337 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 16 Mar 2024 22:12:17 +0000 Subject: Fix #3284 --- src/check_expr.cpp | 2 ++ src/check_stmt.cpp | 6 ++++++ src/parser.hpp | 2 ++ 3 files changed, 10 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 1e4c7499b..3f46e2bdd 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8405,6 +8405,7 @@ gb_internal ExprKind check_or_branch_expr(CheckerContext *c, Operand *o, Ast *no switch (be->token.kind) { case Token_or_break: + node->viral_state_flags |= ViralStateFlag_ContainsOrBreak; if ((c->stmt_flags & Stmt_BreakAllowed) == 0 && label == nullptr) { error(be->token, "'%.*s' only allowed in non-inline loops or 'switch' statements", LIT(name)); } @@ -10254,6 +10255,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast case_end; case_ast_node(re, OrReturnExpr, node); + node->viral_state_flags |= ViralStateFlag_ContainsOrReturn; return check_or_return_expr(c, o, node, type_hint); case_end; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index a7dd9743b..1aa473fd6 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -221,6 +221,12 @@ gb_internal bool check_has_break(Ast *stmt, String const &label, bool implicit) return true; } break; + + case Ast_ExprStmt: + if (stmt->ExprStmt.expr->viral_state_flags & ViralStateFlag_ContainsOrBreak) { + return true; + } + break; } return false; diff --git a/src/parser.hpp b/src/parser.hpp index f410419d4..f5997c4bd 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -310,6 +310,8 @@ enum StateFlag : u8 { enum ViralStateFlag : u8 { ViralStateFlag_ContainsDeferredProcedure = 1<<0, + ViralStateFlag_ContainsOrBreak = 1<<1, + ViralStateFlag_ContainsOrReturn = 1<<2, }; -- cgit v1.2.3 From 43d695a9900ff72064c93ada30a882720af8d489 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 18 Mar 2024 11:21:06 +0000 Subject: Fix `for x in y` where `y` is an "optional ok" value, but ignores `#optional_allocator_error` values --- src/check_expr.cpp | 22 ++++++++++++++-------- src/check_stmt.cpp | 6 +++++- 2 files changed, 19 insertions(+), 9 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3f46e2bdd..0f74a8ccb 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -108,7 +108,7 @@ gb_internal Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint); -gb_internal void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_); +gb_internal void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_, bool change_operand=true); gb_internal void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type); gb_internal void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); @@ -7801,7 +7801,7 @@ gb_internal ExprKind check_implicit_selector_expr(CheckerContext *c, Operand *o, } -gb_internal void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_) { +gb_internal void check_promote_optional_ok(CheckerContext *c, Operand *x, Type **val_type_, Type **ok_type_, bool change_operand) { switch (x->mode) { case Addressing_MapIndex: case Addressing_OptionalOk: @@ -7819,22 +7819,28 @@ gb_internal void check_promote_optional_ok(CheckerContext *c, Operand *x, Type * Type *pt = base_type(type_of_expr(expr->CallExpr.proc)); if (is_type_proc(pt)) { Type *tuple = pt->Proc.results; - add_type_and_value(c, x->expr, x->mode, tuple, x->value); if (pt->Proc.result_count >= 2) { if (ok_type_) *ok_type_ = tuple->Tuple.variables[1]->type; } - expr->CallExpr.optional_ok_one = false; - x->type = tuple; + if (change_operand) { + expr->CallExpr.optional_ok_one = false; + x->type = tuple; + add_type_and_value(c, x->expr, x->mode, tuple, x->value); + } return; } } Type *tuple = make_optional_ok_type(x->type); + if (ok_type_) *ok_type_ = tuple->Tuple.variables[1]->type; - add_type_and_value(c, x->expr, x->mode, tuple, x->value); - x->type = tuple; - GB_ASSERT(is_type_tuple(type_of_expr(x->expr))); + + if (change_operand) { + add_type_and_value(c, x->expr, x->mode, tuple, x->value); + x->type = tuple; + GB_ASSERT(is_type_tuple(type_of_expr(x->expr))); + } } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index d31af08da..a6ca4b9dd 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1544,7 +1544,11 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } } else if (operand.mode != Addressing_Invalid) { if (operand.mode == Addressing_OptionalOk || operand.mode == Addressing_OptionalOkPtr) { - check_promote_optional_ok(ctx, &operand, nullptr, nullptr); + Type *end_type = nullptr; + check_promote_optional_ok(ctx, &operand, nullptr, &end_type, false); + if (is_type_boolean(end_type)) { + check_promote_optional_ok(ctx, &operand, nullptr, &end_type, true); + } } bool is_ptr = is_type_pointer(operand.type); Type *t = base_type(type_deref(operand.type)); -- cgit v1.2.3 From ebd3065aa2806118f1f0868eb633edb72c230aa5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 18 Mar 2024 14:17:13 +0000 Subject: Add error message for C programmers which do `Foo{.x = 123}` rather than `Foo{x = 123}` --- src/check_expr.cpp | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 0f74a8ccb..bea204e2b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8485,18 +8485,26 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slicefield->kind != Ast_Ident) { - gbString expr_str = expr_to_string(fv->field); + Ast *ident = fv->field; + if (ident->kind == Ast_ImplicitSelectorExpr) { + gbString expr_str = expr_to_string(ident); + error(ident, "Field names do not start with a '.', remove the '.' in structure literal", expr_str); + gb_string_free(expr_str); + + ident = ident->ImplicitSelectorExpr.selector; + } + if (ident->kind != Ast_Ident) { + gbString expr_str = expr_to_string(ident); error(elem, "Invalid field name '%s' in structure literal", expr_str); gb_string_free(expr_str); continue; } - String name = fv->field->Ident.token.string; + String name = ident->Ident.token.string; Selection sel = lookup_field(type, name, o->mode == Addressing_Type); bool is_unknown = sel.entity == nullptr; if (is_unknown) { - error(fv->field, "Unknown field '%.*s' in structure literal", LIT(name)); + error(ident, "Unknown field '%.*s' in structure literal", LIT(name)); continue; } @@ -8510,24 +8518,24 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slicefield, field); + add_entity_use(c, ident, field); if (string_set_update(&fields_visited, name)) { if (sel.index.count > 1) { if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { - error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found)); + error(ident, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found)); } else { - error(fv->field, "Duplicate or reused field '%.*s' in %.*s", LIT(sel.entity->token.string), LIT(assignment_str)); + error(ident, "Duplicate or reused field '%.*s' in %.*s", LIT(sel.entity->token.string), LIT(assignment_str)); } } else { - error(fv->field, "Duplicate field '%.*s' in %.*s", LIT(field->token.string), LIT(assignment_str)); + error(ident, "Duplicate field '%.*s' in %.*s", LIT(field->token.string), LIT(assignment_str)); } continue; } else if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { - error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found)); + error(ident, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found)); continue; } if (sel.indirect) { - error(fv->field, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a %.*s", cast(int)sel.index.count-1, LIT(name), LIT(assignment_str)); + error(ident, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a %.*s", cast(int)sel.index.count-1, LIT(name), LIT(assignment_str)); continue; } -- cgit v1.2.3 From 009b6f44e379e7644e0f2987663d52186dea5656 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 18 Mar 2024 15:18:10 +0000 Subject: Add loads of checks for common mistakes for C programmer --- src/check_expr.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index bea204e2b..b58006427 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1539,7 +1539,25 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam if (is_blank_ident(name)) { error(n, "'_' cannot be used as a value"); } else { + ERROR_BLOCK(); error(n, "Undeclared name: %.*s", LIT(name)); + + // NOTE(bill): Loads of checks for C programmers + if (name == "float") { + error_line("\tSuggestion: Did you mean 'f32'?\n"); + } else if (name == "double") { + error_line("\tSuggestion: Did you mean 'f64'?\n"); + } else if (name == "short") { + error_line("\tSuggestion: Did you mean 'i16' or 'c.short' (which is part of 'core:c')?\n"); + } else if (name == "long") { + error_line("\tSuggestion: Did you mean 'c.long' (which is part of 'core:c')?\n"); + } else if (name == "unsigned") { + error_line("\tSuggestion: Did you mean 'c.uint' (which is part of 'core:c')?\n"); + } else if (name == "char") { + error_line("\tSuggestion: Did you mean 'u8', 'i8' or 'c.char' (which is part of 'core:c')?\n"); + } else if (name == "while") { + error_line("\tSuggestion: Did you mean 'for'? Odin only has one loop construct: 'for'\n"); + } } o->type = t_invalid; o->mode = Addressing_Invalid; -- cgit v1.2.3 From 97be7feb99d4ff2b26cde0426c619e50bb0d758a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 18 Mar 2024 17:32:26 +0000 Subject: Add list of C identifier suggestions (types and keywords) --- src/check_expr.cpp | 68 +++++++++++++++++++++++++++++++++++++++++++----------- src/string.cpp | 3 +++ 2 files changed, 57 insertions(+), 14 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b58006427..7da113455 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1528,6 +1528,55 @@ gb_internal bool check_cycle(CheckerContext *c, Entity *curr, bool report) { return false; } +struct CIdentSuggestion { + String name; + String msg; +}; + +// NOTE(bill): this linear look-up table might be slow but because it's an error case, it should be fine +gb_internal CIdentSuggestion const c_ident_suggestions[] = { + {str_lit("while"), str_lit("Did you mean 'for'? Odin only has one loop construct: 'for'")}, + + {str_lit("sizeof"), str_lit("Did you mean 'size_of'?")}, + {str_lit("alignof"), str_lit("Did you mean 'align_of'?")}, + {str_lit("offsetof"), str_lit("Did you mean 'offset_of'?")}, + + {str_lit("_Bool"), str_lit("Did you mean 'bool'?")}, + + {str_lit("char"), str_lit("Did you mean 'u8', 'i8', or 'c.char' (which is part of 'core:c')?")}, + {str_lit("short"), str_lit("Did you mean 'i16' or 'c.short' (which is part of 'core:c')?")}, + {str_lit("long"), str_lit("Did you mean 'c.long' (which is part of 'core:c')?")}, + {str_lit("float"), str_lit("Did you mean 'f32'?")}, + {str_lit("double"), str_lit("Did you mean 'f64'?")}, + {str_lit("unsigned"), str_lit("Did you mean 'c.uint' (which is part of 'core:c')?")}, + {str_lit("signed"), str_lit("Did you mean 'c.int' (which is part of 'core:c')?")}, + + {str_lit("size_t"), str_lit("Did you mean 'uint', or 'c.size_t' (which is part of 'core:c')?")}, + {str_lit("ssize_t"), str_lit("Did you mean 'int', or 'c.ssize_t' (which is part of 'core:c')?")}, + + {str_lit("uintptr_t"), str_lit("Did you mean 'uintptr'?")}, + {str_lit("intptr_t"), str_lit("Did you mean 'uintptr' or `int` or something else?")}, + {str_lit("ptrdiff_t"), str_lit("Did you mean 'int' or 'c.ptrdiff_t' (which is part of 'core:c')?")}, + {str_lit("intmax_t"), str_lit("Dit you mean 'c.intmax_t' (which is part of 'core:c')?")}, + {str_lit("uintmax_t"), str_lit("Dit you mean 'c.uintmax_t' (which is part of 'core:c')?")}, + + {str_lit("uint8_t"), str_lit("Did you mean 'u8'?")}, + {str_lit("int8_t"), str_lit("Did you mean 'i8'?")}, + {str_lit("uint16_t"), str_lit("Did you mean 'u16'?")}, + {str_lit("int16_t"), str_lit("Did you mean 'i16'?")}, + {str_lit("uint32_t"), str_lit("Did you mean 'u32'?")}, + {str_lit("int32_t"), str_lit("Did you mean 'i32'?")}, + {str_lit("uint64_t"), str_lit("Did you mean 'u64'?")}, + {str_lit("int64_t"), str_lit("Did you mean 'i64'?")}, + {str_lit("uint128_t"), str_lit("Did you mean 'u128'?")}, + {str_lit("int128_t"), str_lit("Did you mean 'i128'?")}, + + {str_lit("float32"), str_lit("Did you mean 'f32'?")}, + {str_lit("float64"), str_lit("Did you mean 'f64'?")}, + {str_lit("float32_t"), str_lit("Did you mean 'f32'?")}, + {str_lit("float64_t"), str_lit("Did you mean 'f64'?")}, +}; + gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name) { GB_ASSERT(n->kind == Ast_Ident); o->mode = Addressing_Invalid; @@ -1543,20 +1592,11 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam error(n, "Undeclared name: %.*s", LIT(name)); // NOTE(bill): Loads of checks for C programmers - if (name == "float") { - error_line("\tSuggestion: Did you mean 'f32'?\n"); - } else if (name == "double") { - error_line("\tSuggestion: Did you mean 'f64'?\n"); - } else if (name == "short") { - error_line("\tSuggestion: Did you mean 'i16' or 'c.short' (which is part of 'core:c')?\n"); - } else if (name == "long") { - error_line("\tSuggestion: Did you mean 'c.long' (which is part of 'core:c')?\n"); - } else if (name == "unsigned") { - error_line("\tSuggestion: Did you mean 'c.uint' (which is part of 'core:c')?\n"); - } else if (name == "char") { - error_line("\tSuggestion: Did you mean 'u8', 'i8' or 'c.char' (which is part of 'core:c')?\n"); - } else if (name == "while") { - error_line("\tSuggestion: Did you mean 'for'? Odin only has one loop construct: 'for'\n"); + + for (CIdentSuggestion const &suggestion : c_ident_suggestions) { + if (name == suggestion.name) { + error_line("\tSuggestion: %s\n", LIT(suggestion.msg)); + } } } o->type = t_invalid; diff --git a/src/string.cpp b/src/string.cpp index f762dca40..8be40ec3c 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -106,6 +106,9 @@ gb_internal gb_inline bool str_eq_ignore_case(String const &a, String const &b) template gb_internal gb_inline bool str_eq_ignore_case(String const &a, char const (&b_)[N]) { + if (a.len != N-1) { + return false; + } String b = {cast(u8 *)b_, N-1}; return str_eq_ignore_case(a, b); } -- cgit v1.2.3 From ec9ac593232d8e201639615ba075717dab066752 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 18 Mar 2024 21:37:40 +0000 Subject: Unify "Did you mean" strings --- src/check_expr.cpp | 82 +++++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7da113455..bb31a1646 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1535,46 +1535,46 @@ struct CIdentSuggestion { // NOTE(bill): this linear look-up table might be slow but because it's an error case, it should be fine gb_internal CIdentSuggestion const c_ident_suggestions[] = { - {str_lit("while"), str_lit("Did you mean 'for'? Odin only has one loop construct: 'for'")}, - - {str_lit("sizeof"), str_lit("Did you mean 'size_of'?")}, - {str_lit("alignof"), str_lit("Did you mean 'align_of'?")}, - {str_lit("offsetof"), str_lit("Did you mean 'offset_of'?")}, - - {str_lit("_Bool"), str_lit("Did you mean 'bool'?")}, - - {str_lit("char"), str_lit("Did you mean 'u8', 'i8', or 'c.char' (which is part of 'core:c')?")}, - {str_lit("short"), str_lit("Did you mean 'i16' or 'c.short' (which is part of 'core:c')?")}, - {str_lit("long"), str_lit("Did you mean 'c.long' (which is part of 'core:c')?")}, - {str_lit("float"), str_lit("Did you mean 'f32'?")}, - {str_lit("double"), str_lit("Did you mean 'f64'?")}, - {str_lit("unsigned"), str_lit("Did you mean 'c.uint' (which is part of 'core:c')?")}, - {str_lit("signed"), str_lit("Did you mean 'c.int' (which is part of 'core:c')?")}, - - {str_lit("size_t"), str_lit("Did you mean 'uint', or 'c.size_t' (which is part of 'core:c')?")}, - {str_lit("ssize_t"), str_lit("Did you mean 'int', or 'c.ssize_t' (which is part of 'core:c')?")}, - - {str_lit("uintptr_t"), str_lit("Did you mean 'uintptr'?")}, - {str_lit("intptr_t"), str_lit("Did you mean 'uintptr' or `int` or something else?")}, - {str_lit("ptrdiff_t"), str_lit("Did you mean 'int' or 'c.ptrdiff_t' (which is part of 'core:c')?")}, - {str_lit("intmax_t"), str_lit("Dit you mean 'c.intmax_t' (which is part of 'core:c')?")}, - {str_lit("uintmax_t"), str_lit("Dit you mean 'c.uintmax_t' (which is part of 'core:c')?")}, - - {str_lit("uint8_t"), str_lit("Did you mean 'u8'?")}, - {str_lit("int8_t"), str_lit("Did you mean 'i8'?")}, - {str_lit("uint16_t"), str_lit("Did you mean 'u16'?")}, - {str_lit("int16_t"), str_lit("Did you mean 'i16'?")}, - {str_lit("uint32_t"), str_lit("Did you mean 'u32'?")}, - {str_lit("int32_t"), str_lit("Did you mean 'i32'?")}, - {str_lit("uint64_t"), str_lit("Did you mean 'u64'?")}, - {str_lit("int64_t"), str_lit("Did you mean 'i64'?")}, - {str_lit("uint128_t"), str_lit("Did you mean 'u128'?")}, - {str_lit("int128_t"), str_lit("Did you mean 'i128'?")}, - - {str_lit("float32"), str_lit("Did you mean 'f32'?")}, - {str_lit("float64"), str_lit("Did you mean 'f64'?")}, - {str_lit("float32_t"), str_lit("Did you mean 'f32'?")}, - {str_lit("float64_t"), str_lit("Did you mean 'f64'?")}, + {str_lit("while"), str_lit("'for'? Odin only has one loop construct: 'for'")}, + + {str_lit("sizeof"), str_lit("'size_of'?")}, + {str_lit("alignof"), str_lit("'align_of'?")}, + {str_lit("offsetof"), str_lit("'offset_of'?")}, + + {str_lit("_Bool"), str_lit("'bool'?")}, + + {str_lit("char"), str_lit("'u8', 'i8', or 'c.char' (which is part of 'core:c')?")}, + {str_lit("short"), str_lit("'i16' or 'c.short' (which is part of 'core:c')?")}, + {str_lit("long"), str_lit("'c.long' (which is part of 'core:c')?")}, + {str_lit("float"), str_lit("'f32'?")}, + {str_lit("double"), str_lit("'f64'?")}, + {str_lit("unsigned"), str_lit("'c.uint' (which is part of 'core:c')?")}, + {str_lit("signed"), str_lit("'c.int' (which is part of 'core:c')?")}, + + {str_lit("size_t"), str_lit("'uint', or 'c.size_t' (which is part of 'core:c')?")}, + {str_lit("ssize_t"), str_lit("'int', or 'c.ssize_t' (which is part of 'core:c')?")}, + + {str_lit("uintptr_t"), str_lit("'uintptr'?")}, + {str_lit("intptr_t"), str_lit("'uintptr' or `int` or something else?")}, + {str_lit("ptrdiff_t"), str_lit("'int' or 'c.ptrdiff_t' (which is part of 'core:c')?")}, + {str_lit("intmax_t"), str_lit("'c.intmax_t' (which is part of 'core:c')?")}, + {str_lit("uintmax_t"), str_lit("'c.uintmax_t' (which is part of 'core:c')?")}, + + {str_lit("uint8_t"), str_lit("'u8'?")}, + {str_lit("int8_t"), str_lit("'i8'?")}, + {str_lit("uint16_t"), str_lit("'u16'?")}, + {str_lit("int16_t"), str_lit("'i16'?")}, + {str_lit("uint32_t"), str_lit("'u32'?")}, + {str_lit("int32_t"), str_lit("'i32'?")}, + {str_lit("uint64_t"), str_lit("'u64'?")}, + {str_lit("int64_t"), str_lit("'i64'?")}, + {str_lit("uint128_t"), str_lit("'u128'?")}, + {str_lit("int128_t"), str_lit("'i128'?")}, + + {str_lit("float32"), str_lit("'f32'?")}, + {str_lit("float64"), str_lit("'f64'?")}, + {str_lit("float32_t"), str_lit("'f32'?")}, + {str_lit("float64_t"), str_lit("'f64'?")}, }; gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name) { @@ -1595,7 +1595,7 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam for (CIdentSuggestion const &suggestion : c_ident_suggestions) { if (name == suggestion.name) { - error_line("\tSuggestion: %s\n", LIT(suggestion.msg)); + error_line("\tSuggestion: Did you mean %s\n", LIT(suggestion.msg)); } } } -- cgit v1.2.3 From 80ecf5b68aa02a2445aa4cbf3d1d46ed5a007d75 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 19 Mar 2024 13:32:37 +0000 Subject: On `x: [?]T = {...}`, minimize errors by using the `[?]T` expression as a kind of hint --- src/check_expr.cpp | 47 ++++++++++++++++++++++++++++++++++++++--------- src/check_stmt.cpp | 12 +++++++----- src/checker.hpp | 1 + 3 files changed, 46 insertions(+), 14 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index bb31a1646..ed6182928 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8672,6 +8672,24 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slicekind == Ast_ArrayType && type_expr->ArrayType.count != nullptr) { + Ast *count = type_expr->ArrayType.count; + if (count->kind == Ast_UnaryExpr && + count->UnaryExpr.op.kind == Token_Question) { + return true; + } + } + return false; +} + gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; ast_node(cl, CompoundLit, node); @@ -8682,20 +8700,31 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } bool is_to_be_determined_array_count = false; bool is_constant = true; - if (cl->type != nullptr) { + + Ast *type_expr = cl->type; + + bool used_type_hint_expr = false; + if (type_expr == nullptr && c->type_hint_expr != nullptr) { + if (is_expr_inferred_fixed_array(c->type_hint_expr)) { + type_expr = clone_ast(c->type_hint_expr); + used_type_hint_expr = true; + } + } + + if (type_expr != nullptr) { type = nullptr; // [?]Type - if (cl->type->kind == Ast_ArrayType && cl->type->ArrayType.count != nullptr) { - Ast *count = cl->type->ArrayType.count; + if (type_expr->kind == Ast_ArrayType && type_expr->ArrayType.count != nullptr) { + Ast *count = type_expr->ArrayType.count; if (count->kind == Ast_UnaryExpr && count->UnaryExpr.op.kind == Token_Question) { - type = alloc_type_array(check_type(c, cl->type->ArrayType.elem), -1); + type = alloc_type_array(check_type(c, type_expr->ArrayType.elem), -1); is_to_be_determined_array_count = true; } if (cl->elems.count > 0) { - if (cl->type->ArrayType.tag != nullptr) { - Ast *tag = cl->type->ArrayType.tag; + if (type_expr->ArrayType.tag != nullptr) { + Ast *tag = type_expr->ArrayType.tag; GB_ASSERT(tag->kind == Ast_BasicDirective); String name = tag->BasicDirective.name.string; if (name == "soa") { @@ -8705,9 +8734,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } } } - if (cl->type->kind == Ast_DynamicArrayType && cl->type->DynamicArrayType.tag != nullptr) { + if (type_expr->kind == Ast_DynamicArrayType && type_expr->DynamicArrayType.tag != nullptr) { if (cl->elems.count > 0) { - Ast *tag = cl->type->DynamicArrayType.tag; + Ast *tag = type_expr->DynamicArrayType.tag; GB_ASSERT(tag->kind == Ast_BasicDirective); String name = tag->BasicDirective.name.string; if (name == "soa") { @@ -8718,7 +8747,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } if (type == nullptr) { - type = check_type(c, cl->type); + type = check_type(c, type_expr); } } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index a6ca4b9dd..4280e7578 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1919,17 +1919,19 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f e->Variable.thread_local_model = ac.thread_local_model; } - if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) { - // error(e->token, "@(thread_local) is not supported for this target platform"); - } - - if (ac.is_static && ac.thread_local_model != "") { error(e->token, "The 'static' attribute is not needed if 'thread_local' is applied"); } } + // NOTE(bill): This is to improve error handling for things like `x: [?]T = {...}` + Ast *prev_type_hint_expr = ctx->type_hint_expr; + ctx->type_hint_expr = vd->type; + check_init_variables(ctx, entities, entity_count, vd->values, str_lit("variable declaration")); + + ctx->type_hint_expr = prev_type_hint_expr; + check_arity_match(ctx, vd, false); for (isize i = 0; i < entity_count; i++) { diff --git a/src/checker.hpp b/src/checker.hpp index 066d6bb4a..eea99578e 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -451,6 +451,7 @@ struct CheckerContext { u32 state_flags; bool in_defer; Type * type_hint; + Ast * type_hint_expr; String proc_name; DeclInfo * curr_proc_decl; -- cgit v1.2.3 From 8ff788f4fff7504b8b6bca1183a9be98b8765cbc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 19 Mar 2024 13:38:13 +0000 Subject: Add better suggestion for [?]T mistake --- src/check_expr.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ed6182928..236d44a43 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -119,6 +119,8 @@ gb_internal bool is_diverging_expr(Ast *expr); gb_internal isize get_procedure_param_count_excluding_defaults(Type *pt, isize *param_count_); +gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr); + enum LoadDirectiveResult { LoadDirective_Success = 0, LoadDirective_Error = 1, @@ -2242,6 +2244,10 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o error_line("\tSuggestion: the expression may be casted to %s\n", b); } else if (check_integer_exceed_suggestion(c, o, type, max_bit_size)) { return; + } else if (is_expr_inferred_fixed_array(c->type_hint_expr) && is_type_array_like(type) && is_type_array_like(o->type)) { + gbString s = expr_to_string(c->type_hint_expr); + error_line("\tSuggestion: make sure that `%s` is attached to the compound literal directly\n", s); + gb_string_free(s); } } @@ -8678,7 +8684,6 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) { return false; } - // [?]Type if (type_expr->kind == Ast_ArrayType && type_expr->ArrayType.count != nullptr) { Ast *count = type_expr->ArrayType.count; -- 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_expr.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 a750fc0ba63c9f1461bba4cc0446b1b4c2d2b3a9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 19 Mar 2024 21:05:23 +0000 Subject: Add `#row_major matrix[R, C]T` As well as `#column_major matrix[R, C]T` as an alias for just `matrix[R, C]T`. This is because some libraries require a row_major internal layout but still want to be used with row or major oriented vectors. --- base/runtime/core.odin | 4 ++++ core/fmt/fmt.odin | 12 ++++++++++-- core/reflect/types.odin | 4 ++++ src/check_expr.cpp | 12 +++++++++--- src/check_type.cpp | 2 +- src/llvm_backend_const.cpp | 4 ++-- src/llvm_backend_expr.cpp | 39 +++++++++++++++++++++++++++++---------- src/llvm_backend_type.cpp | 3 ++- src/llvm_backend_utility.cpp | 22 +++++++++++++++------- src/parser.cpp | 13 +++++++++++++ src/parser.hpp | 1 + src/types.cpp | 19 +++++++++++++++---- 12 files changed, 105 insertions(+), 30 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 8f27ca674..7ad3ef1d6 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -177,6 +177,10 @@ Type_Info_Matrix :: struct { row_count: int, column_count: int, // Total element count = column_count * elem_stride + layout: enum u8 { + Column_Major, // array of column vectors + Row_Major, // array of row vectors + }, } Type_Info_Soa_Pointer :: struct { elem: ^Type_Info, diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 02803f882..6f9801bc8 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -2396,7 +2396,11 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix for col in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - offset := (row + col*info.elem_stride)*info.elem_size + offset: int + switch info.layout { + case .Column_Major: offset = (row + col*info.elem_stride)*info.elem_size + case .Row_Major: offset = (col + row*info.elem_stride)*info.elem_size + } data := uintptr(v.data) + uintptr(offset) fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) @@ -2410,7 +2414,11 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix for col in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - offset := (row + col*info.elem_stride)*info.elem_size + offset: int + switch info.layout { + case .Column_Major: offset = (row + col*info.elem_stride)*info.elem_size + case .Row_Major: offset = (col + row*info.elem_stride)*info.elem_size + } data := uintptr(v.data) + uintptr(offset) fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 2b96dd4fb..9cff46a00 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -173,6 +173,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { y := b.variant.(Type_Info_Matrix) or_return if x.row_count != y.row_count { return false } if x.column_count != y.column_count { return false } + if x.layout != y.layout { return false } return are_types_identical(x.elem, y.elem) case Type_Info_Bit_Field: @@ -689,6 +690,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) - write_type(w, info.pointer, &n) or_return case Type_Info_Matrix: + if info.layout == .Row_Major { + io.write_string(w, "#row_major ", &n) or_return + } io.write_string(w, "matrix[", &n) or_return io.write_i64(w, i64(info.row_count), 10, &n) or_return io.write_string(w, ", ", &n) or_return diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f359d5a54..67c7f1a04 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3431,6 +3431,11 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand if (xt->Matrix.column_count != yt->Matrix.row_count) { goto matrix_error; } + + if (xt->Matrix.is_row_major != yt->Matrix.is_row_major) { + goto matrix_error; + } + x->mode = Addressing_Value; if (are_types_identical(xt, yt)) { if (!is_type_named(x->type) && is_type_named(y->type)) { @@ -3438,7 +3443,8 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand x->type = y->type; } } else { - x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count); + bool is_row_major = xt->Matrix.is_row_major && yt->Matrix.is_row_major; + x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count, nullptr, nullptr, is_row_major); } goto matrix_success; } else if (yt->kind == Type_Array) { @@ -3452,7 +3458,7 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand // Treat arrays as column vectors x->mode = Addressing_Value; - if (type_hint == nullptr && xt->Matrix.row_count == yt->Array.count) { + 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); @@ -3483,7 +3489,7 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand // Treat arrays as row vectors x->mode = Addressing_Value; - if (type_hint == nullptr && yt->Matrix.column_count == xt->Array.count) { + 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); diff --git a/src/check_type.cpp b/src/check_type.cpp index d5cf187a4..3fe633892 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2658,7 +2658,7 @@ gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) } type_assign:; - *type = alloc_type_matrix(elem, row_count, column_count, generic_row, generic_column); + *type = alloc_type_matrix(elem, row_count, column_count, generic_row, generic_column, mt->is_row_major); return; } diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 2291f24ac..bbb0b8387 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1302,11 +1302,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo GB_ASSERT_MSG(elem_count == max_count, "%td != %td", elem_count, max_count); LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)total_count); - for_array(i, cl->elems) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - i64 offset = matrix_row_major_index_to_offset(type, i); + i64 offset = 0; + offset = matrix_row_major_index_to_offset(type, i); values[offset] = lb_const_value(m, elem_type, tav.value, allow_local).value; } for (isize i = 0; i < total_count; i++) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 98618798b..6eb8fdcc6 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -684,12 +684,6 @@ gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type Type *mt = base_type(m.type); GB_ASSERT(mt->kind == Type_Matrix); - // TODO(bill): Determine why this fails on Windows sometimes - if (false && lb_is_matrix_simdable(mt)) { - LLVMValueRef vector = lb_matrix_to_trimmed_vector(p, m); - return lb_matrix_cast_vector_to_type(p, vector, type); - } - lbAddr res = lb_add_local_generated(p, type, true); i64 row_count = mt->Matrix.row_count; @@ -763,6 +757,7 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, GB_ASSERT(is_type_matrix(yt)); GB_ASSERT(xt->Matrix.column_count == yt->Matrix.row_count); GB_ASSERT(are_types_identical(xt->Matrix.elem, yt->Matrix.elem)); + GB_ASSERT(xt->Matrix.is_row_major == yt->Matrix.is_row_major); Type *elem = xt->Matrix.elem; @@ -770,7 +765,7 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, unsigned inner = cast(unsigned)xt->Matrix.column_count; unsigned outer_columns = cast(unsigned)yt->Matrix.column_count; - if (lb_is_matrix_simdable(xt)) { + if (!xt->Matrix.is_row_major && lb_is_matrix_simdable(xt)) { unsigned x_stride = cast(unsigned)matrix_type_stride_in_elems(xt); unsigned y_stride = cast(unsigned)matrix_type_stride_in_elems(yt); @@ -812,7 +807,7 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, return lb_addr_load(p, res); } - { + if (!xt->Matrix.is_row_major) { lbAddr res = lb_add_local_generated(p, type, true); auto inners = slice_make(permanent_allocator(), inner); @@ -835,6 +830,30 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, } } + return lb_addr_load(p, res); + } else { + lbAddr res = lb_add_local_generated(p, type, true); + + auto inners = slice_make(permanent_allocator(), inner); + + for (unsigned i = 0; i < outer_rows; i++) { + for (unsigned j = 0; j < outer_columns; j++) { + lbValue dst = lb_emit_matrix_epi(p, res.addr, i, j); + for (unsigned k = 0; k < inner; k++) { + inners[k][0] = lb_emit_matrix_ev(p, lhs, i, k); + inners[k][1] = lb_emit_matrix_ev(p, rhs, k, j); + } + + lbValue sum = lb_const_nil(p->module, elem); + for (unsigned k = 0; k < inner; k++) { + lbValue a = inners[k][0]; + lbValue b = inners[k][1]; + sum = lb_emit_mul_add(p, a, b, sum, elem); + } + lb_emit_store(p, dst, sum); + } + } + return lb_addr_load(p, res); } } @@ -855,7 +874,7 @@ gb_internal lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbVal Type *elem = mt->Matrix.elem; - if (lb_is_matrix_simdable(mt)) { + if (!mt->Matrix.is_row_major && lb_is_matrix_simdable(mt)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; @@ -924,7 +943,7 @@ gb_internal lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbVal Type *elem = mt->Matrix.elem; - if (lb_is_matrix_simdable(mt)) { + if (!mt->Matrix.is_row_major && lb_is_matrix_simdable(mt)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index aec1fb201..de83f5058 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -979,12 +979,13 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ tag_type = t_type_info_matrix; i64 ez = type_size_of(t->Matrix.elem); - LLVMValueRef vals[5] = { + LLVMValueRef vals[6] = { get_type_info_ptr(m, t->Matrix.elem), lb_const_int(m, t_int, ez).value, lb_const_int(m, t_int, matrix_type_stride_in_elems(t)).value, lb_const_int(m, t_int, t->Matrix.row_count).value, lb_const_int(m, t_int, t->Matrix.column_count).value, + lb_const_int(m, t_u8, cast(u8)t->Matrix.is_row_major).value, }; variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index f18aa5521..fb61c41c3 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1464,14 +1464,16 @@ gb_internal lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isi Type *t = s.type; GB_ASSERT(is_type_pointer(t)); Type *mt = base_type(type_deref(t)); - if (column == 0) { - GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt)); - return lb_emit_epi(p, s, row); - } else if (row == 0 && is_type_array_like(mt)) { - return lb_emit_epi(p, s, column); + + if (!mt->Matrix.is_row_major) { + if (column == 0) { + GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt)); + return lb_emit_epi(p, s, row); + } else if (row == 0 && is_type_array_like(mt)) { + return lb_emit_epi(p, s, column); + } } - GB_ASSERT_MSG(is_type_matrix(mt), "%s", type_to_string(mt)); isize offset = matrix_indices_to_offset(mt, row, column); @@ -1491,7 +1493,13 @@ gb_internal lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lb row = lb_emit_conv(p, row, t_int); column = lb_emit_conv(p, column, t_int); - LLVMValueRef index = LLVMBuildAdd(p->builder, row.value, LLVMBuildMul(p->builder, column.value, stride_elems, ""), ""); + LLVMValueRef index = nullptr; + + if (mt->Matrix.is_row_major) { + index = LLVMBuildAdd(p->builder, column.value, LLVMBuildMul(p->builder, row.value, stride_elems, ""), ""); + } else { + index = LLVMBuildAdd(p->builder, row.value, LLVMBuildMul(p->builder, column.value, stride_elems, ""), ""); + } LLVMValueRef indices[2] = { LLVMConstInt(lb_type(p->module, t_int), 0, false), diff --git a/src/parser.cpp b/src/parser.cpp index 1aa40ccbf..eb9e73342 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2329,6 +2329,19 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { break; } return original_type; + } else if (name.string == "row_major" || + name.string == "column_major") { + Ast *original_type = parse_type(f); + Ast *type = unparen_expr(original_type); + switch (type->kind) { + case Ast_MatrixType: + type->MatrixType.is_row_major = (name.string == "row_major"); + break; + default: + syntax_error(type, "Expected a matrix type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind])); + break; + } + return original_type; } else if (name.string == "partial") { Ast *tag = ast_basic_directive(f, token, name); Ast *original_expr = parse_expr(f, lhs); diff --git a/src/parser.hpp b/src/parser.hpp index f5997c4bd..ff3c5eb34 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -772,6 +772,7 @@ AST_KIND(_TypeBegin, "", bool) \ Ast *row_count; \ Ast *column_count; \ Ast *elem; \ + bool is_row_major; \ }) \ AST_KIND(_TypeEnd, "", bool) diff --git a/src/types.cpp b/src/types.cpp index 5a3ad5d6b..ab5e4de03 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -281,6 +281,7 @@ struct TypeProc { Type *generic_row_count; \ Type *generic_column_count; \ i64 stride_in_bytes; \ + bool is_row_major; \ }) \ TYPE_KIND(BitField, struct { \ Scope * scope; \ @@ -1002,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) { +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) { if (generic_row_count != nullptr || generic_column_count != nullptr) { Type *t = alloc_type(Type_Matrix); t->Matrix.elem = elem; @@ -1010,12 +1011,14 @@ gb_internal Type *alloc_type_matrix(Type *elem, i64 row_count, i64 column_count, t->Matrix.column_count = column_count; t->Matrix.generic_row_count = generic_row_count; t->Matrix.generic_column_count = generic_column_count; + t->Matrix.is_row_major = is_row_major; return t; } Type *t = alloc_type(Type_Matrix); t->Matrix.elem = elem; t->Matrix.row_count = row_count; t->Matrix.column_count = column_count; + t->Matrix.is_row_major = is_row_major; return t; } @@ -1512,14 +1515,18 @@ gb_internal i64 matrix_indices_to_offset(Type *t, i64 row_index, i64 column_inde GB_ASSERT(0 <= row_index && row_index < t->Matrix.row_count); GB_ASSERT(0 <= column_index && column_index < t->Matrix.column_count); i64 stride_elems = matrix_type_stride_in_elems(t); - // NOTE(bill): Column-major layout internally - return row_index + stride_elems*column_index; + if (t->Matrix.is_row_major) { + return column_index + stride_elems*row_index; + } else { + // NOTE(bill): Column-major layout internally + return row_index + stride_elems*column_index; + } } gb_internal i64 matrix_row_major_index_to_offset(Type *t, i64 index) { t = base_type(t); GB_ASSERT(t->kind == Type_Matrix); - + i64 row_index = index/t->Matrix.column_count; i64 column_index = index%t->Matrix.column_count; return matrix_indices_to_offset(t, row_index, column_index); @@ -2690,6 +2697,7 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_Matrix: return x->Matrix.row_count == y->Matrix.row_count && x->Matrix.column_count == y->Matrix.column_count && + x->Matrix.is_row_major == y->Matrix.is_row_major && are_types_identical(x->Matrix.elem, y->Matrix.elem); case Type_DynamicArray: @@ -4735,6 +4743,9 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha break; case Type_Matrix: + if (type->Matrix.is_row_major) { + str = gb_string_appendc(str, "#row_major "); + } str = gb_string_appendc(str, gb_bprintf("matrix[%d, %d]", cast(int)type->Matrix.row_count, cast(int)type->Matrix.column_count)); str = write_type_to_string(str, type->Matrix.elem); break; -- 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_expr.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 b1dae2d59ab1f35992d0f24b4f01d4d2123f9262 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 20 Mar 2024 13:28:17 +0000 Subject: Add `x: T; y: ^T = x` suggestion to do `&x` --- src/check_expr.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e9a6f5122..e22d57814 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2248,6 +2248,12 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o gbString s = expr_to_string(c->type_hint_expr); error_line("\tSuggestion: make sure that `%s` is attached to the compound literal directly\n", s); gb_string_free(s); + } else if (is_type_pointer(type) && + o->mode == Addressing_Variable && + are_types_identical(type_deref(type), o->type)) { + gbString s = expr_to_string(o->expr); + error_line("\tSuggestion: Did you mean `&%s`\n", s); + gb_string_free(s); } } -- cgit v1.2.3 From ba77a9464c7e912dda52dd512dc98f3c241581ac Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 20 Mar 2024 13:36:14 +0000 Subject: Add suggestion for `x: ^T; y = x` to be `x^` --- src/check_expr.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e22d57814..8fb2cf36b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2254,6 +2254,11 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o gbString s = expr_to_string(o->expr); error_line("\tSuggestion: Did you mean `&%s`\n", s); gb_string_free(s); + } else if (is_type_pointer(o->type) && + are_types_identical(type_deref(o->type), type)) { + gbString s = expr_to_string(o->expr); + error_line("\tSuggestion: Did you mean `%s^`\n", s); + gb_string_free(s); } } -- cgit v1.2.3 From 29e5f94c2a0d666eed93a1013f895f3c86d6373f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 21 Mar 2024 11:52:48 +0000 Subject: Add `#no_broadcast` procedure parameter to disallow automatic array programming broadcasting on procedure arguments --- base/runtime/core_builtin.odin | 12 +++---- core/image/common.odin | 36 ++++++++++---------- core/math/big/prime.odin | 2 +- core/odin/ast/ast.odin | 16 +++++---- core/thread/thread.odin | 2 +- src/check_expr.cpp | 76 ++++++++++++++++++++++++++---------------- src/check_type.cpp | 16 ++++++++- src/entity.cpp | 1 + src/parser.cpp | 17 +++++----- src/parser.hpp | 3 +- vendor/raylib/raymath.odin | 4 +-- 11 files changed, 113 insertions(+), 72 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index 401dcb857..fba2e1328 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -447,12 +447,12 @@ _append_elem :: #force_inline proc(array: ^$T/[dynamic]$E, arg: E, should_zero: } @builtin -append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { return _append_elem(array, arg, true, loc=loc) } @builtin -non_zero_append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +non_zero_append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { return _append_elem(array, arg, false, loc=loc) } @@ -496,12 +496,12 @@ _append_elems :: #force_inline proc(array: ^$T/[dynamic]$E, should_zero: bool, l } @builtin -append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { return _append_elems(array, true, loc, ..args) } @builtin -non_zero_append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +non_zero_append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { return _append_elems(array, false, loc, ..args) } @@ -556,7 +556,7 @@ append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: i @builtin -inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { +inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { if array == nil { return } @@ -574,7 +574,7 @@ inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle } @builtin -inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { +inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { if array == nil { return } diff --git a/core/image/common.odin b/core/image/common.odin index c7507a85f..b576a9521 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -651,7 +651,7 @@ alpha_add_if_missing :: proc(img: ^Image, alpha_key := Alpha_Key{}, allocator := // We have keyed alpha. o: GA_Pixel for p in inp { - if p == key.r { + if p.r == key.r { o = GA_Pixel{0, key.g} } else { o = GA_Pixel{p.r, 255} @@ -710,7 +710,7 @@ alpha_add_if_missing :: proc(img: ^Image, alpha_key := Alpha_Key{}, allocator := // We have keyed alpha. o: GA_Pixel_16 for p in inp { - if p == key.r { + if p.r == key.r { o = GA_Pixel_16{0, key.g} } else { o = GA_Pixel_16{p.r, 65535} @@ -842,11 +842,11 @@ alpha_drop_if_present :: proc(img: ^Image, options := Options{}, alpha_key := Al bg := G_Pixel{} if temp_bg, temp_bg_ok := img.background.(RGB_Pixel_16); temp_bg_ok { // Background is RGB 16-bit, take just the red channel's topmost byte. - bg = u8(temp_bg.r >> 8) + bg.r = u8(temp_bg.r >> 8) } for p in inp { - out[0] = bg if p == key else p + out[0] = bg if p.r == key else p out = out[1:] } @@ -865,8 +865,8 @@ alpha_drop_if_present :: proc(img: ^Image, options := Options{}, alpha_key := Al for p in inp { a := f32(p.g) / 255.0 c := ((1.0 - a) * bg + a * f32(p.r)) - out[0] = u8(c) - out = out[1:] + out[0].r = u8(c) + out = out[1:] } } else if .alpha_premultiply in options { @@ -874,14 +874,14 @@ alpha_drop_if_present :: proc(img: ^Image, options := Options{}, alpha_key := Al for p in inp { a := f32(p.g) / 255.0 c := f32(p.r) * a - out[0] = u8(c) - out = out[1:] + out[0].r = u8(c) + out = out[1:] } } else { // Just drop alpha on the floor. for p in inp { - out[0] = p.r - out = out[1:] + out[0].r = p.r + out = out[1:] } } @@ -951,11 +951,11 @@ alpha_drop_if_present :: proc(img: ^Image, options := Options{}, alpha_key := Al bg := G_Pixel_16{} if temp_bg, temp_bg_ok := img.background.(RGB_Pixel_16); temp_bg_ok { // Background is RGB 16-bit, take just the red channel. - bg = temp_bg.r + bg.r = temp_bg.r } for p in inp { - out[0] = bg if p == key else p + out[0] = bg if p.r == key else p out = out[1:] } @@ -974,8 +974,8 @@ alpha_drop_if_present :: proc(img: ^Image, options := Options{}, alpha_key := Al for p in inp { a := f32(p.g) / 65535.0 c := ((1.0 - a) * bg + a * f32(p.r)) - out[0] = u16(c) - out = out[1:] + out[0].r = u16(c) + out = out[1:] } } else if .alpha_premultiply in options { @@ -983,14 +983,14 @@ alpha_drop_if_present :: proc(img: ^Image, options := Options{}, alpha_key := Al for p in inp { a := f32(p.g) / 65535.0 c := f32(p.r) * a - out[0] = u16(c) - out = out[1:] + out[0].r = u16(c) + out = out[1:] } } else { // Just drop alpha on the floor. for p in inp { - out[0] = p.r - out = out[1:] + out[0].r = p.r + out = out[1:] } } diff --git a/core/math/big/prime.odin b/core/math/big/prime.odin index cb0b08dbb..b02b7cb4e 100644 --- a/core/math/big/prime.odin +++ b/core/math/big/prime.odin @@ -1112,7 +1112,7 @@ internal_int_prime_next_prime :: proc(a: ^Int, trials: int, bbs_style: bool, all Generate the restable. */ for x := 1; x < _PRIME_TAB_SIZE; x += 1 { - res_tab = internal_mod(a, _private_prime_table[x]) or_return + res_tab = cast(type_of(res_tab))(internal_mod(a, _private_prime_table[x]) or_return) } for { diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index f6bcbab4e..3e215e0f2 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -597,6 +597,7 @@ Field_Flag :: enum { Any_Int, Subtype, By_Ptr, + No_Broadcast, Results, Tags, @@ -616,6 +617,7 @@ field_flag_strings := [Field_Flag]string{ .Any_Int = "#any_int", .Subtype = "#subtype", .By_Ptr = "#by_ptr", + .No_Broadcast ="#no_broadcast", .Results = "results", .Tags = "field tag", @@ -624,12 +626,13 @@ field_flag_strings := [Field_Flag]string{ } field_hash_flag_strings := []struct{key: string, flag: Field_Flag}{ - {"no_alias", .No_Alias}, - {"c_vararg", .C_Vararg}, - {"const", .Const}, - {"any_int", .Any_Int}, - {"subtype", .Subtype}, - {"by_ptr", .By_Ptr}, + {"no_alias", .No_Alias}, + {"c_vararg", .C_Vararg}, + {"const", .Const}, + {"any_int", .Any_Int}, + {"subtype", .Subtype}, + {"by_ptr", .By_Ptr}, + {"no_broadcast", .No_Broadcast}, } @@ -650,6 +653,7 @@ Field_Flags_Signature :: Field_Flags{ .Const, .Any_Int, .By_Ptr, + .No_Broadcast, .Default_Parameters, } diff --git a/core/thread/thread.odin b/core/thread/thread.odin index 1c473bd1d..55f73d106 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -163,7 +163,7 @@ create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_co t := create(thread_proc, priority) t.data = rawptr(fn) t.user_index = 1 - t.user_args = data + t.user_args[0] = data if self_cleanup { t.flags += {.Self_Cleanup} } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8fb2cf36b..51fe3fc8a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -623,7 +623,7 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type); #define MAXIMUM_TYPE_DISTANCE 10 -gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type) { +gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type, bool allow_array_programming) { if (c == nullptr) { GB_ASSERT(operand->mode == Addressing_Value); GB_ASSERT(is_type_typed(operand->type)); @@ -832,7 +832,7 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand if (dst->Union.variants.count == 1) { Type *vt = dst->Union.variants[0]; - i64 score = check_distance_between_types(c, operand, vt); + i64 score = check_distance_between_types(c, operand, vt, allow_array_programming); if (score >= 0) { return score+2; } @@ -840,7 +840,7 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand i64 prev_lowest_score = -1; i64 lowest_score = -1; for (Type *vt : dst->Union.variants) { - i64 score = check_distance_between_types(c, operand, vt); + i64 score = check_distance_between_types(c, operand, vt, allow_array_programming); if (score >= 0) { if (lowest_score < 0) { lowest_score = score; @@ -863,14 +863,14 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand } if (is_type_relative_pointer(dst)) { - i64 score = check_distance_between_types(c, operand, dst->RelativePointer.pointer_type); + i64 score = check_distance_between_types(c, operand, dst->RelativePointer.pointer_type, allow_array_programming); if (score >= 0) { return score+2; } } if (is_type_relative_multi_pointer(dst)) { - i64 score = check_distance_between_types(c, operand, dst->RelativeMultiPointer.pointer_type); + i64 score = check_distance_between_types(c, operand, dst->RelativeMultiPointer.pointer_type, allow_array_programming); if (score >= 0) { return score+2; } @@ -896,19 +896,21 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand } } - if (is_type_array(dst)) { - Type *elem = base_array_type(dst); - i64 distance = check_distance_between_types(c, operand, elem); - if (distance >= 0) { - return distance + 6; + if (allow_array_programming) { + if (is_type_array(dst)) { + Type *elem = base_array_type(dst); + i64 distance = check_distance_between_types(c, operand, elem, allow_array_programming); + if (distance >= 0) { + return distance + 6; + } } - } - if (is_type_simd_vector(dst)) { - Type *dst_elem = base_array_type(dst); - i64 distance = check_distance_between_types(c, operand, dst_elem); - if (distance >= 0) { - return distance + 6; + if (is_type_simd_vector(dst)) { + Type *dst_elem = base_array_type(dst); + i64 distance = check_distance_between_types(c, operand, dst_elem, allow_array_programming); + if (distance >= 0) { + return distance + 6; + } } } @@ -918,7 +920,7 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand } if (dst->Matrix.row_count == dst->Matrix.column_count) { Type *dst_elem = base_array_type(dst); - i64 distance = check_distance_between_types(c, operand, dst_elem); + i64 distance = check_distance_between_types(c, operand, dst_elem, allow_array_programming); if (distance >= 0) { return distance + 7; } @@ -966,9 +968,9 @@ gb_internal i64 assign_score_function(i64 distance, bool is_variadic=false) { } -gb_internal bool check_is_assignable_to_with_score(CheckerContext *c, Operand *operand, Type *type, i64 *score_, bool is_variadic=false) { +gb_internal bool check_is_assignable_to_with_score(CheckerContext *c, Operand *operand, Type *type, i64 *score_, bool is_variadic=false, bool allow_array_programming=true) { i64 score = 0; - i64 distance = check_distance_between_types(c, operand, type); + i64 distance = check_distance_between_types(c, operand, type, allow_array_programming); bool ok = distance >= 0; if (ok) { score = assign_score_function(distance, is_variadic); @@ -978,9 +980,9 @@ gb_internal bool check_is_assignable_to_with_score(CheckerContext *c, Operand *o } -gb_internal bool check_is_assignable_to(CheckerContext *c, Operand *operand, Type *type) { +gb_internal bool check_is_assignable_to(CheckerContext *c, Operand *operand, Type *type, bool allow_array_programming=true) { i64 score = 0; - return check_is_assignable_to_with_score(c, operand, type, &score); + return check_is_assignable_to_with_score(c, operand, type, &score, /*is_variadic*/false, allow_array_programming); } gb_internal bool internal_check_is_assignable_to(Type *src, Type *dst) { @@ -3142,6 +3144,14 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type return true; } + + if (is_type_array(dst)) { + Type *elem = base_array_type(dst); + if (check_is_castable_to(c, operand, elem)) { + return true; + } + } + if (is_type_simd_vector(src) && is_type_simd_vector(dst)) { if (src->SimdVector.count != dst->SimdVector.count) { return false; @@ -5853,15 +5863,20 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } } - auto eval_param_and_score = [](CheckerContext *c, Operand *o, Type *param_type, CallArgumentError &err, bool param_is_variadic, Entity *e, bool show_error) -> i64 { + auto eval_param_and_score = [](CheckerContext *c, Operand *o, Type *param_type, CallArgumentError &err, bool param_is_variadic, Entity *e, bool show_error, bool allow_array_programming) -> i64 { i64 s = 0; - if (!check_is_assignable_to_with_score(c, o, param_type, &s, param_is_variadic)) { + if (!check_is_assignable_to_with_score(c, o, param_type, &s, param_is_variadic, allow_array_programming)) { bool ok = false; - if (e && e->flags & EntityFlag_AnyInt) { + if (e && (e->flags & EntityFlag_AnyInt)) { if (is_type_integer(param_type)) { ok = check_is_castable_to(c, o, param_type); } } + if (!allow_array_programming && check_is_assignable_to_with_score(c, o, param_type, nullptr, param_is_variadic, !allow_array_programming)) { + if (show_error) { + error(o->expr, "'#no_broadcast' disallows automatic broadcasting a value across all elements of an array-like type in a procedure argument"); + } + } if (ok) { s = assign_score_function(MAXIMUM_TYPE_DISTANCE); } else { @@ -5878,7 +5893,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } err = CallArgumentError_WrongTypes; } - } else if (show_error) { check_assignment(c, o, param_type, str_lit("procedure argument")); } @@ -5963,12 +5977,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A if (param_is_variadic) { continue; } - score += eval_param_and_score(c, o, e->type, err, param_is_variadic, e, show_error); + bool allow_array_programming = !(e && (e->flags & EntityFlag_NoBroadcast)); + score += eval_param_and_score(c, o, e->type, err, param_is_variadic, e, show_error, allow_array_programming); } } if (variadic) { - Type *slice = pt->params->Tuple.variables[pt->variadic_index]->type; + Entity *var_entity = pt->params->Tuple.variables[pt->variadic_index]; + Type *slice = var_entity->type; GB_ASSERT(is_type_slice(slice)); Type *elem = base_type(slice)->Slice.elem; Type *t = elem; @@ -5994,7 +6010,8 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A return CallArgumentError_MultipleVariadicExpand; } } - score += eval_param_and_score(c, o, t, err, true, nullptr, show_error); + bool allow_array_programming = !(var_entity && (var_entity->flags & EntityFlag_NoBroadcast)); + score += eval_param_and_score(c, o, t, err, true, nullptr, show_error, allow_array_programming); } } @@ -11148,6 +11165,9 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan if (f->flags&FieldFlag_any_int) { str = gb_string_appendc(str, "#any_int "); } + if (f->flags&FieldFlag_no_broadcast) { + str = gb_string_appendc(str, "#no_broadcast "); + } if (f->flags&FieldFlag_const) { str = gb_string_appendc(str, "#const "); } diff --git a/src/check_type.cpp b/src/check_type.cpp index 3fe633892..96885bd27 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1869,6 +1869,10 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para error(name, "'#any_int' can only be applied to variable fields"); p->flags &= ~FieldFlag_any_int; } + if (p->flags&FieldFlag_no_broadcast) { + error(name, "'#no_broadcast' can only be applied to variable fields"); + p->flags &= ~FieldFlag_no_broadcast; + } if (p->flags&FieldFlag_by_ptr) { error(name, "'#by_ptr' can only be applied to variable fields"); p->flags &= ~FieldFlag_by_ptr; @@ -1926,7 +1930,13 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para } } } - if (type != t_invalid && !check_is_assignable_to(ctx, &op, type)) { + + bool allow_array_programming = true; + if (p->flags&FieldFlag_no_broadcast) { + allow_array_programming = false; + } + + if (type != t_invalid && !check_is_assignable_to(ctx, &op, type, allow_array_programming)) { bool ok = true; if (p->flags&FieldFlag_any_int) { if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) { @@ -2002,6 +2012,10 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (p->flags&FieldFlag_no_alias) { param->flags |= EntityFlag_NoAlias; } + if (p->flags&FieldFlag_no_broadcast) { + param->flags |= EntityFlag_NoBroadcast; + } + if (p->flags&FieldFlag_any_int) { if (!is_type_integer(param->type) && !is_type_enum(param->type)) { gbString str = type_to_string(param->type); diff --git a/src/entity.cpp b/src/entity.cpp index 916c2b2bd..9161ea733 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -61,6 +61,7 @@ enum EntityFlag : u64 { EntityFlag_CVarArg = 1ull<<22, + EntityFlag_NoBroadcast = 1ull<<23, EntityFlag_AnyInt = 1ull<<24, EntityFlag_Disabled = 1ull<<25, diff --git a/src/parser.cpp b/src/parser.cpp index 6a7be8a7c..b6b62461f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3898,14 +3898,15 @@ struct ParseFieldPrefixMapping { FieldFlag flag; }; -gb_global ParseFieldPrefixMapping parse_field_prefix_mappings[] = { - {str_lit("using"), Token_using, FieldFlag_using}, - {str_lit("no_alias"), Token_Hash, FieldFlag_no_alias}, - {str_lit("c_vararg"), Token_Hash, FieldFlag_c_vararg}, - {str_lit("const"), Token_Hash, FieldFlag_const}, - {str_lit("any_int"), Token_Hash, FieldFlag_any_int}, - {str_lit("subtype"), Token_Hash, FieldFlag_subtype}, - {str_lit("by_ptr"), Token_Hash, FieldFlag_by_ptr}, +gb_global ParseFieldPrefixMapping const parse_field_prefix_mappings[] = { + {str_lit("using"), Token_using, FieldFlag_using}, + {str_lit("no_alias"), Token_Hash, FieldFlag_no_alias}, + {str_lit("c_vararg"), Token_Hash, FieldFlag_c_vararg}, + {str_lit("const"), Token_Hash, FieldFlag_const}, + {str_lit("any_int"), Token_Hash, FieldFlag_any_int}, + {str_lit("subtype"), Token_Hash, FieldFlag_subtype}, + {str_lit("by_ptr"), Token_Hash, FieldFlag_by_ptr}, + {str_lit("no_broadcast"), Token_Hash, FieldFlag_no_broadcast}, }; diff --git a/src/parser.hpp b/src/parser.hpp index ff3c5eb34..5820275c8 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -326,6 +326,7 @@ enum FieldFlag : u32 { FieldFlag_any_int = 1<<6, FieldFlag_subtype = 1<<7, FieldFlag_by_ptr = 1<<8, + FieldFlag_no_broadcast = 1<<9, // disallow array programming // Internal use by the parser only FieldFlag_Tags = 1<<10, @@ -336,7 +337,7 @@ enum FieldFlag : u32 { FieldFlag_Invalid = 1u<<31, // Parameter List Restrictions - FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr, + FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr|FieldFlag_no_broadcast, FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags, }; diff --git a/vendor/raylib/raymath.odin b/vendor/raylib/raymath.odin index beeda7989..9682ffe4f 100644 --- a/vendor/raylib/raymath.odin +++ b/vendor/raylib/raymath.odin @@ -159,7 +159,7 @@ Vector2Transform :: proc "c" (v: Vector2, m: Matrix) -> Vector2 { // Calculate linear interpolation between two vectors @(require_results, deprecated="Prefer = linalg.lerp(v1, v2, amount)") Vector2Lerp :: proc "c" (v1, v2: Vector2, amount: f32) -> Vector2 { - return linalg.lerp(v1, v2, amount) + return linalg.lerp(v1, v2, Vector2(amount)) } // Calculate reflected vector to normal @(require_results, deprecated="Prefer = linalg.reflect(v, normal)") @@ -405,7 +405,7 @@ Vector3Transform :: proc "c" (v: Vector3, m: Matrix) -> Vector3 { // Calculate linear interpolation between two vectors @(require_results, deprecated="Prefer = linalg.lerp(v1, v2, amount)") Vector3Lerp :: proc "c" (v1, v2: Vector3, amount: f32) -> Vector3 { - return linalg.lerp(v1, v2, amount) + return linalg.lerp(v1, v2, Vector3(amount)) } // Calculate reflected vector to normal @(require_results, deprecated="Prefer = linalg.reflect(v, normal)") -- cgit v1.2.3 From 010ffc486cb22b21136fdfa4f5ad04532767fa70 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 21 Mar 2024 11:54:40 +0000 Subject: Minor clean up of `#no_broadcast` handling --- src/check_expr.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 51fe3fc8a..1f060506a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5863,7 +5863,8 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } } - auto eval_param_and_score = [](CheckerContext *c, Operand *o, Type *param_type, CallArgumentError &err, bool param_is_variadic, Entity *e, bool show_error, bool allow_array_programming) -> i64 { + auto eval_param_and_score = [](CheckerContext *c, Operand *o, Type *param_type, CallArgumentError &err, bool param_is_variadic, Entity *e, bool show_error) -> i64 { + bool allow_array_programming = !(e && (e->flags & EntityFlag_NoBroadcast)); i64 s = 0; if (!check_is_assignable_to_with_score(c, o, param_type, &s, param_is_variadic, allow_array_programming)) { bool ok = false; @@ -5977,8 +5978,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A if (param_is_variadic) { continue; } - bool allow_array_programming = !(e && (e->flags & EntityFlag_NoBroadcast)); - score += eval_param_and_score(c, o, e->type, err, param_is_variadic, e, show_error, allow_array_programming); + score += eval_param_and_score(c, o, e->type, err, false, e, show_error); } } @@ -6010,8 +6010,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A return CallArgumentError_MultipleVariadicExpand; } } - bool allow_array_programming = !(var_entity && (var_entity->flags & EntityFlag_NoBroadcast)); - score += eval_param_and_score(c, o, t, err, true, nullptr, show_error, allow_array_programming); + score += eval_param_and_score(c, o, t, err, true, var_entity, show_error); } } -- cgit v1.2.3 From 6b6f72e7bd3030c53d7a59dacdcb28146340188d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 21 Mar 2024 14:59:47 +0000 Subject: Fix #3305 --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 1f060506a..97ceea600 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1599,7 +1599,7 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam for (CIdentSuggestion const &suggestion : c_ident_suggestions) { if (name == suggestion.name) { - error_line("\tSuggestion: Did you mean %s\n", LIT(suggestion.msg)); + error_line("\tSuggestion: Did you mean %.*s\n", LIT(suggestion.msg)); } } } -- cgit v1.2.3 From d47ba09743446f787d5b427e52d189cc91d47529 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 21 Mar 2024 20:43:52 +0000 Subject: Fix at error printing bug --- src/check_expr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 97ceea600..bb573e1e4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6138,7 +6138,10 @@ gb_internal bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Sco } } - if (call_expr) error(call_expr, "at caller location"); + if (call_expr) { + TokenPos pos = ast_token(call_expr).pos; + error_line("%s at caller location\n", token_pos_to_string(pos)); + } } return false; } -- cgit v1.2.3 From 7abb459861f5501b55893d1d2cf7590268f1dfb2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 23 Mar 2024 12:56:04 +0000 Subject: Add missing field flags in debug printing --- src/check_expr.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index bb573e1e4..d1f393bef 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -11236,6 +11236,18 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan if (field->flags&FieldFlag_c_vararg) { str = gb_string_appendc(str, "#c_vararg "); } + if (field->flags&FieldFlag_any_int) { + str = gb_string_appendc(str, "#any_int "); + } + if (field->flags&FieldFlag_no_broadcast) { + str = gb_string_appendc(str, "#no_broadcast "); + } + if (field->flags&FieldFlag_const) { + str = gb_string_appendc(str, "#const "); + } + if (field->flags&FieldFlag_subtype) { + str = gb_string_appendc(str, "#subtype "); + } str = write_expr_to_string(str, field->type, shorthand); } -- cgit v1.2.3 From 1d46adb598328b4977d5b4cfad2a1dc679b05a21 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 23 Mar 2024 16:51:04 +0000 Subject: Treat `*x` as an unary operator to improve error messages for common C-programmer mistakes --- src/check_expr.cpp | 13 +++++++++++++ src/check_type.cpp | 16 +++++++++++++++- src/parser.cpp | 7 ++++++- 3 files changed, 34 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d1f393bef..f09c8fe3c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1800,6 +1800,19 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) { } break; + case Token_Mul: + { + ERROR_BLOCK(); + error(op, "Operator '%.*s' is not a valid unary operator in Odin", LIT(op.string)); + if (is_type_pointer(o->type)) { + str = expr_to_string(o->expr); + error_line("\tSuggestion: Did you mean '%s^'?\n", str); + } else if (is_type_multi_pointer(o->type)) { + str = expr_to_string(o->expr); + error_line("\tSuggestion: The value is a multi-pointer, did you mean '%s[0]'?\n", str); + } + } + break; default: error(op, "Unknown operator '%.*s'", LIT(op.string)); return false; diff --git a/src/check_type.cpp b/src/check_type.cpp index 38bfa56ef..0b9042905 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -3375,7 +3375,9 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) type = t_invalid; - // NOTE(bill): Check for common mistakes from C programmers e.g. T[] and T[N] + // NOTE(bill): Check for common mistakes from C programmers + // e.g. T[] and T[N] + // e.g. *T Ast *node = unparen_expr(e); if (node && node->kind == Ast_IndexExpr) { gbString index_str = nullptr; @@ -3395,6 +3397,18 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) Ast *pseudo_array_expr = ast_array_type(e->file(), ast_token(node->IndexExpr.expr), node->IndexExpr.index, node->IndexExpr.expr); check_array_type_internal(ctx, pseudo_array_expr, &type, nullptr); } + } else if (node && node->kind == Ast_UnaryExpr && node->UnaryExpr.op.kind == Token_Mul) { + gbString type_str = expr_to_string(node->UnaryExpr.expr); + defer (gb_string_free(type_str)); + + error_line("\tSuggestion: Did you mean '^%s'?\n", type_str); + end_error_block(); + + // NOTE(bill): Minimize error propagation of bad array syntax by treating this like a type + if (node->UnaryExpr.expr != nullptr) { + Ast *pseudo_pointer_expr = ast_pointer_type(e->file(), ast_token(node->UnaryExpr.expr), node->UnaryExpr.expr); + return check_type_expr(ctx, pseudo_pointer_expr, named_type); + } } else { end_error_block(); } diff --git a/src/parser.cpp b/src/parser.cpp index b6b62461f..bb9a526fe 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2541,6 +2541,9 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { return ast_pointer_type(f, token, elem); } break; + case Token_Mul: + return parse_unary_expr(f, true); + case Token_OpenBracket: { Token token = expect_token(f, Token_OpenBracket); Ast *count_expr = nullptr; @@ -3274,7 +3277,9 @@ gb_internal Ast *parse_unary_expr(AstFile *f, bool lhs) { case Token_Sub: case Token_Xor: case Token_And: - case Token_Not: { + case Token_Not: + case Token_Mul: // Used for error handling when people do C-like things + { Token token = advance_token(f); Ast *expr = parse_unary_expr(f, lhs); return ast_unary_expr(f, token, expr); -- cgit v1.2.3 From eb51cc6835a202d0a5fde297d87277041fc433e7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 23 Mar 2024 16:53:40 +0000 Subject: Improve error propagation for `(*x).y` style errors from C-programmers --- src/check_expr.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f09c8fe3c..ab8fe78fc 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1807,9 +1807,11 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) { if (is_type_pointer(o->type)) { str = expr_to_string(o->expr); error_line("\tSuggestion: Did you mean '%s^'?\n", str); + o->type = type_deref(o->type); } else if (is_type_multi_pointer(o->type)) { str = expr_to_string(o->expr); error_line("\tSuggestion: The value is a multi-pointer, did you mean '%s[0]'?\n", str); + o->type = type_deref(o->type, true); } } break; -- cgit v1.2.3 From efb0933965669a5b4b8c5534d4f77fc29ddab732 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 23 Mar 2024 16:57:35 +0000 Subject: Improve error suggestion and propagation for `x->y` --- src/check_expr.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ab8fe78fc..80008d73a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4900,10 +4900,18 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod Selection sel = {}; // NOTE(bill): Not used if it's an import name if (!c->allow_arrow_right_selector_expr && se->token.kind == Token_ArrowRight) { + ERROR_BLOCK(); error(node, "Illegal use of -> selector shorthand outside of a call"); - operand->mode = Addressing_Invalid; - operand->expr = node; - return nullptr; + gbString x = expr_to_string(se->expr); + gbString y = expr_to_string(se->selector); + error_line("\tSuggestion: Did you mean '%s.%s'?\n", x, y); + gb_string_free(y); + gb_string_free(x); + + // TODO(bill): Should this terminate here or propagate onwards? + // operand->mode = Addressing_Invalid; + // operand->expr = node; + // return nullptr; } operand->expr = node; -- 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_expr.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 6da6393735dd18d68b1f4662a157f6044f87b470 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 24 Mar 2024 13:40:10 +0000 Subject: Fix #3320 --- src/check_expr.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ecc8a804c..bd2c576cf 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1174,6 +1174,16 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ type_str, type_extra, LIT(context_name)); check_assignment_error_suggestion(c, operand, type); + + if (context_name == "procedure argument") { + Type *src = base_type(operand->type); + Type *dst = base_type(type); + if (is_type_slice(src) && are_types_identical(src->Slice.elem, dst)) { + gbString a = expr_to_string(operand->expr); + error_line("\tSuggestion: Did you mean to pass the slice into the variadic parameter with ..%s?\n\n", a); + gb_string_free(a); + } + } } break; } @@ -5905,16 +5915,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); - Type *dst = base_type(param_type); - if (is_type_slice(src) && are_types_identical(src->Slice.elem, dst)) { - gbString a = expr_to_string(o->expr); - error_line("\tSuggestion: Did you mean to pass the slice into the variadic parameter with ..%s?\n\n", a); - gb_string_free(a); - } } err = CallArgumentError_WrongTypes; } -- cgit v1.2.3 From d92767cb7784fab76663a82eb84db680af6ec6f6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 24 Mar 2024 13:49:51 +0000 Subject: Fix #3226 --- src/check_expr.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index bd2c576cf..fd10374c1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5830,10 +5830,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A Operand *variadic_operand = &ordered_operands[pt->variadic_index]; if (vari_expand) { - GB_ASSERT(variadic_operands.count != 0); - *variadic_operand = variadic_operands[0]; - variadic_operand->type = default_type(variadic_operand->type); - actually_variadic = true; + if (variadic_operands.count == 0) { + error(call, "'..' in the wrong position"); + } else { + GB_ASSERT(variadic_operands.count != 0); + *variadic_operand = variadic_operands[0]; + variadic_operand->type = default_type(variadic_operand->type); + actually_variadic = true; + } } else { AstFile *f = call->file(); -- 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_expr.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 e5629dafd0be1be42a3bd183a09ff82492b6b386 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 25 Mar 2024 13:23:43 +0000 Subject: Potentially fix a race condition with parapoly types (related to #3328) --- src/check_expr.cpp | 11 +++- src/check_type.cpp | 179 +++++++++++++++++++++++++++-------------------------- src/checker.hpp | 9 ++- src/threading.cpp | 2 - 4 files changed, 104 insertions(+), 97 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fd10374c1..44d65e376 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -79,7 +79,6 @@ gb_internal Type * check_type_expr (CheckerContext *c, Ast *exp gb_internal Type * make_optional_ok_type (Type *value, bool typed=true); gb_internal Entity * check_selector (CheckerContext *c, Operand *operand, Ast *node, Type *type_hint); gb_internal Entity * check_ident (CheckerContext *c, Operand *o, Ast *n, Type *named_type, Type *type_hint, bool allow_import_name); -gb_internal Entity * find_polymorphic_record_entity (CheckerContext *c, Type *original_type, isize param_count, Array const &ordered_operands, bool *failure); gb_internal void check_not_tuple (CheckerContext *c, Operand *operand); gb_internal void convert_to_typed (CheckerContext *c, Operand *operand, Type *target_type); gb_internal gbString expr_to_string (Ast *expression); @@ -121,6 +120,8 @@ gb_internal isize get_procedure_param_count_excluding_defaults(Type *pt, isize * gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr); +gb_internal Entity *find_polymorphic_record_entity(GenTypesData *found_gen_types, isize param_count, Array const &ordered_operands); + enum LoadDirectiveResult { LoadDirective_Success = 0, LoadDirective_Error = 1, @@ -7171,8 +7172,12 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O } { - bool failure = false; - Entity *found_entity = find_polymorphic_record_entity(c, original_type, param_count, ordered_operands, &failure); + GenTypesData *found_gen_types = ensure_polymorphic_record_entity_has_gen_types(c, original_type); + + mutex_lock(&found_gen_types->mutex); + defer (mutex_unlock(&found_gen_types->mutex)); + Entity *found_entity = find_polymorphic_record_entity(found_gen_types, param_count, ordered_operands); + if (found_entity) { operand->mode = Addressing_Type; operand->type = found_entity->type; diff --git a/src/check_type.cpp b/src/check_type.cpp index 0b9042905..e22d4b62b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -260,84 +260,21 @@ gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_, } -gb_internal Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array const &ordered_operands, bool *failure) { - rw_mutex_shared_lock(&ctx->info->gen_types_mutex); // @@global - - auto *found_gen_types = map_get(&ctx->info->gen_types, original_type); - if (found_gen_types == nullptr) { - rw_mutex_shared_unlock(&ctx->info->gen_types_mutex); // @@global - return nullptr; - } - - rw_mutex_shared_lock(&found_gen_types->mutex); // @@local - defer (rw_mutex_shared_unlock(&found_gen_types->mutex)); // @@local - - rw_mutex_shared_unlock(&ctx->info->gen_types_mutex); // @@global - - 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; - } - GB_ASSERT_MSG(tuple != nullptr, "%s :: %s", type_to_string(e->type), type_to_string(t)); - GB_ASSERT(param_count == tuple->variables.count); - - bool skip = false; - - for (isize j = 0; j < param_count; j++) { - Entity *p = tuple->variables[j]; - Operand o = {}; - if (j < ordered_operands.count) { - o = ordered_operands[j]; - } - if (o.expr == nullptr) { - continue; - } - Entity *oe = entity_of_node(o.expr); - if (p == oe) { - // NOTE(bill): This is the same type, make sure that it will be be same thing and use that - // Saves on a lot of checking too below - continue; - } - - if (p->kind == Entity_TypeName) { - if (is_type_polymorphic(o.type)) { - // NOTE(bill): Do not add polymorphic version to the gen_types - skip = true; - break; - } - if (!are_types_identical(o.type, p->type)) { - skip = true; - break; - } - } else if (p->kind == Entity_Constant) { - if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) { - skip = true; - break; - } - if (!are_types_identical(o.type, p->type)) { - skip = true; - break; - } - } else { - GB_PANIC("Unknown entity kind"); - } - } - if (!skip) { - return e; - } +gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type) { + mutex_lock(&ctx->info->gen_types_mutex); // @@global + + GenTypesData *found_gen_types = nullptr; + auto *found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type); + if (found_gen_types_ptr == nullptr) { + GenTypesData *gen_types = gb_alloc_item(permanent_allocator(), GenTypesData); + gen_types->types = array_make(heap_allocator()); + map_set(&ctx->info->gen_types, original_type, gen_types); + found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type); } - return nullptr; + found_gen_types = *found_gen_types_ptr; + GB_ASSERT(found_gen_types != nullptr); + mutex_unlock(&ctx->info->gen_types_mutex); // @@global + return found_gen_types; } @@ -367,19 +304,16 @@ gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, T // TODO(bill): Is this even correct? Or should the metadata be copied? e->TypeName.objc_metadata = original_type->Named.type_name->TypeName.objc_metadata; - rw_mutex_lock(&ctx->info->gen_types_mutex); - auto *found_gen_types = map_get(&ctx->info->gen_types, original_type); - if (found_gen_types) { - rw_mutex_lock(&found_gen_types->mutex); - array_add(&found_gen_types->types, e); - rw_mutex_unlock(&found_gen_types->mutex); - } else { - GenTypesData gen_types = {}; - gen_types.types = array_make(heap_allocator()); - array_add(&gen_types.types, e); - map_set(&ctx->info->gen_types, original_type, gen_types); + auto *found_gen_types = ensure_polymorphic_record_entity_has_gen_types(ctx, original_type); + mutex_lock(&found_gen_types->mutex); + defer (mutex_unlock(&found_gen_types->mutex)); + + for (Entity *prev : found_gen_types->types) { + if (prev == e) { + return; + } } - rw_mutex_unlock(&ctx->info->gen_types_mutex); + array_add(&found_gen_types->types, e); } @@ -612,6 +546,73 @@ gb_internal bool check_record_poly_operand_specialization(CheckerContext *ctx, T return true; } +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; + } + GB_ASSERT_MSG(tuple != nullptr, "%s :: %s", type_to_string(e->type), type_to_string(t)); + GB_ASSERT(param_count == tuple->variables.count); + + bool skip = false; + + for (isize j = 0; j < param_count; j++) { + Entity *p = tuple->variables[j]; + Operand o = {}; + if (j < ordered_operands.count) { + o = ordered_operands[j]; + } + if (o.expr == nullptr) { + continue; + } + Entity *oe = entity_of_node(o.expr); + if (p == oe) { + // NOTE(bill): This is the same type, make sure that it will be be same thing and use that + // Saves on a lot of checking too below + continue; + } + + if (p->kind == Entity_TypeName) { + if (is_type_polymorphic(o.type)) { + // NOTE(bill): Do not add polymorphic version to the gen_types + skip = true; + break; + } + if (!are_types_identical(o.type, p->type)) { + skip = true; + break; + } + } else if (p->kind == Entity_Constant) { + if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) { + skip = true; + break; + } + if (!are_types_identical(o.type, p->type)) { + skip = true; + break; + } + } else { + GB_PANIC("Unknown entity kind"); + } + } + if (!skip) { + return e; + } + } + return nullptr; +}; + gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array *poly_operands, Type *named_type, Type *original_type_for_poly) { GB_ASSERT(is_type_struct(struct_type)); diff --git a/src/checker.hpp b/src/checker.hpp index eea99578e..e0dc54a87 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -360,7 +360,7 @@ struct GenProcsData { struct GenTypesData { Array types; - RwMutex mutex; + RecursiveMutex mutex; }; // CheckerInfo stores all the symbol information for a type-checked program @@ -400,8 +400,8 @@ struct CheckerInfo { RecursiveMutex lazy_mutex; // Mutex required for lazy type checking of specific files - RwMutex gen_types_mutex; - PtrMap gen_types; + BlockingMutex gen_types_mutex; + PtrMap gen_types; BlockingMutex type_info_mutex; // NOT recursive Array type_info_types; @@ -560,3 +560,6 @@ gb_internal void init_core_context(Checker *c); gb_internal void init_mem_allocator(Checker *c); gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped); + + +gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type); \ No newline at end of file diff --git a/src/threading.cpp b/src/threading.cpp index a469435d2..d9538f66e 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -122,8 +122,6 @@ gb_internal void wait_signal_set(Wait_Signal *ws) { futex_broadcast(&ws->futex); } - - struct MutexGuard { MutexGuard() = delete; MutexGuard(MutexGuard const &) = delete; -- cgit v1.2.3 From 50618759a65bfbc09e9f7b62878ecefff78ab1be Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 25 Mar 2024 13:44:00 +0000 Subject: Fix error reporting for type cycles --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 0dc6fdb02..a34b425c2 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1738,7 +1738,7 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam if (check_cycle(c, e, true)) { o->type = t_invalid; } - if (o->type != nullptr && type->kind == Type_Named && o->type->Named.type_name->TypeName.is_type_alias) { + if (o->type != nullptr && o->type->kind == Type_Named && o->type->Named.type_name->TypeName.is_type_alias) { o->type = base_type(o->type); } -- cgit v1.2.3 From 1009182f7b35e38e0fba375ad830fc609a7be831 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 26 Mar 2024 14:13:55 +0000 Subject: Fix another #soa race condition bug --- src/check_expr.cpp | 5 ++++ src/check_type.cpp | 60 ++++++++++++++++++++++++++++++----------------- src/checker.cpp | 31 ++++++++++++++++++++++++ src/checker.hpp | 1 + src/llvm_backend_type.cpp | 2 +- src/types.cpp | 2 ++ 6 files changed, 78 insertions(+), 23 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index a34b425c2..3a275729f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -122,6 +122,8 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr); gb_internal Entity *find_polymorphic_record_entity(GenTypesData *found_gen_types, isize param_count, Array const &ordered_operands); +gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finish); + enum LoadDirectiveResult { LoadDirective_Success = 0, LoadDirective_Error = 1, @@ -5031,6 +5033,9 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } } + if (operand->type && is_type_soa_struct(type_deref(operand->type))) { + complete_soa_type(c->checker, type_deref(operand->type), false); + } if (entity == nullptr && selector->kind == Ast_Ident) { String field_name = selector->Ident.token.string; diff --git a/src/check_type.cpp b/src/check_type.cpp index d26d9b660..40a7ec947 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2690,17 +2690,19 @@ struct SoaTypeWorkerData { }; -gb_internal void complete_soa_type(CheckerContext *ctx, Type *t, bool wait_to_finish) { +gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finish) { Type *original_type = t; + gb_unused(original_type); + t = base_type(t); if (t == nullptr || !is_type_soa_struct(t)) { - return; + return true; } MUTEX_GUARD(&t->Struct.soa_mutex); if (t->Struct.fields_wait_signal.futex.load()) { - return; + return true; } isize field_count = 0; @@ -2711,8 +2713,6 @@ gb_internal void complete_soa_type(CheckerContext *ctx, Type *t, bool wait_to_fi case StructSoa_Dynamic: extra_field_count = 3; break; } - - Ast *node = t->Struct.node; Scope *scope = t->Struct.scope; i64 soa_count = t->Struct.soa_count; Type *elem = t->Struct.soa_elem; @@ -2721,18 +2721,26 @@ gb_internal void complete_soa_type(CheckerContext *ctx, Type *t, bool wait_to_fi if (wait_to_finish) { wait_signal_until_available(&old_struct->Struct.fields_wait_signal); + } else { + GB_ASSERT(old_struct->Struct.fields_wait_signal.futex.load()); } - field_count = old_struct->Struct.fields.count; t->Struct.fields = slice_make(permanent_allocator(), field_count+extra_field_count); t->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count); - if (soa_count > I32_MAX) { - soa_count = I32_MAX; - error(node, "Array count too large for an #soa struct, got %lld", cast(long long)soa_count); - } - t->Struct.soa_count = cast(i32)soa_count; + + + auto const &add_entity = [](Scope *scope, Entity *entity) { + String name = entity->token.string; + if (!is_blank_ident(name)) { + Entity *ie = scope_insert(scope, entity); + if (ie != nullptr) { + redeclaration_error(name, entity, ie); + } + } + }; + for_array(i, old_struct->Struct.fields) { Entity *old_field = old_struct->Struct.fields[i]; @@ -2746,8 +2754,8 @@ gb_internal void complete_soa_type(CheckerContext *ctx, Type *t, bool wait_to_fi } Entity *new_field = alloc_entity_field(scope, old_field->token, field_type, false, old_field->Variable.field_index); t->Struct.fields[i] = new_field; - add_entity(ctx, scope, nullptr, new_field); - add_entity_use(ctx, nullptr, new_field); + add_entity(scope, new_field); + new_field->flags |= EntityFlag_Used; } else { t->Struct.fields[i] = old_field; } @@ -2758,29 +2766,32 @@ gb_internal void complete_soa_type(CheckerContext *ctx, Type *t, bool wait_to_fi if (t->Struct.soa_kind != StructSoa_Fixed) { Entity *len_field = alloc_entity_field(scope, make_token_ident("__$len"), t_int, false, cast(i32)field_count+0); t->Struct.fields[field_count+0] = len_field; - add_entity(ctx, scope, nullptr, len_field); - add_entity_use(ctx, nullptr, len_field); + add_entity(scope, len_field); + len_field->flags |= EntityFlag_Used; if (t->Struct.soa_kind == StructSoa_Dynamic) { Entity *cap_field = alloc_entity_field(scope, make_token_ident("__$cap"), t_int, false, cast(i32)field_count+1); t->Struct.fields[field_count+1] = cap_field; - add_entity(ctx, scope, nullptr, cap_field); - add_entity_use(ctx, nullptr, cap_field); + add_entity(scope, cap_field); + cap_field->flags |= EntityFlag_Used; - init_mem_allocator(ctx->checker); + init_mem_allocator(checker); Entity *allocator_field = alloc_entity_field(scope, make_token_ident("allocator"), t_allocator, false, cast(i32)field_count+2); t->Struct.fields[field_count+2] = allocator_field; - add_entity(ctx, scope, nullptr, allocator_field); - add_entity_use(ctx, nullptr, allocator_field); + add_entity(scope, allocator_field); + allocator_field->flags |= EntityFlag_Used; } } - add_type_info_type(ctx, original_type); + // add_type_info_type(ctx, original_type); + + wait_signal_set(&t->Struct.fields_wait_signal); + return true; } gb_internal WORKER_TASK_PROC(complete_soa_type_worker) { SoaTypeWorkerData *wd = cast(SoaTypeWorkerData *)data; - complete_soa_type(&wd->ctx, wd->type, wd->wait_to_finish); + complete_soa_type(wd->ctx.checker, wd->type, wd->wait_to_finish); return 0; } @@ -2825,6 +2836,9 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e scope = create_scope(ctx->info, ctx->scope); soa_struct->Struct.scope = scope; + if (elem && elem->kind == Type_Named) { + add_declaration_dependency(ctx, elem->Named.type_name); + } if (is_polymorphic) { field_count = 0; @@ -2938,6 +2952,8 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e wd->ctx = *ctx; wd->type = soa_struct; wd->wait_to_finish = true; + + mpsc_enqueue(&ctx->checker->soa_types_to_complete, soa_struct); thread_pool_add_task(complete_soa_type_worker, wd); } diff --git a/src/checker.cpp b/src/checker.cpp index e7d0ad9cb..ccda31a4f 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1371,6 +1371,7 @@ gb_internal void init_checker(Checker *c) { array_init(&c->nested_proc_lits, heap_allocator(), 0, 1<<20); mpsc_init(&c->global_untyped_queue, a); // , 1<<20); + mpsc_init(&c->soa_types_to_complete, a); // , 1<<20); c->builtin_ctx = make_checker_context(c); } @@ -1383,6 +1384,7 @@ gb_internal void destroy_checker(Checker *c) { array_free(&c->nested_proc_lits); array_free(&c->procs_to_check); mpsc_destroy(&c->global_untyped_queue); + mpsc_destroy(&c->soa_types_to_complete); } @@ -1682,6 +1684,26 @@ gb_internal bool add_entity_with_name(CheckerContext *c, Scope *scope, Ast *iden } return true; } + +gb_internal bool add_entity_with_name(CheckerInfo *info, Scope *scope, Ast *identifier, Entity *entity, String name) { + if (scope == nullptr) { + return false; + } + + + if (!is_blank_ident(name)) { + Entity *ie = scope_insert(scope, entity); + if (ie != nullptr) { + return redeclaration_error(name, entity, ie); + } + } + if (identifier != nullptr) { + GB_ASSERT(entity->file != nullptr); + add_entity_definition(info, identifier, entity); + } + return true; +} + gb_internal bool add_entity(CheckerContext *c, Scope *scope, Ast *identifier, Entity *entity) { return add_entity_with_name(c, scope, identifier, entity, entity->token.string); } @@ -4440,6 +4462,10 @@ gb_internal void check_all_global_entities(Checker *c) { DeclInfo *d = e->decl_info; check_single_global_entity(c, e, d); if (e->type != nullptr && is_type_typed(e->type)) { + for (Type *t = nullptr; mpsc_dequeue(&c->soa_types_to_complete, &t); /**/) { + complete_soa_type(c, t, false); + } + (void)type_size_of(e->type); (void)type_align_of(e->type); } @@ -6108,6 +6134,9 @@ gb_internal void check_add_definitions_from_queues(Checker *c) { } gb_internal void check_merge_queues_into_arrays(Checker *c) { + for (Type *t = nullptr; mpsc_dequeue(&c->soa_types_to_complete, &t); /**/) { + complete_soa_type(c, t, false); + } check_add_entities_from_queues(c); check_add_definitions_from_queues(c); } @@ -6318,6 +6347,8 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("check bodies have all been checked"); check_unchecked_bodies(c); + TIME_SECTION("check #soa types"); + check_merge_queues_into_arrays(c); thread_pool_wait(); diff --git a/src/checker.hpp b/src/checker.hpp index e0dc54a87..1701da58d 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -500,6 +500,7 @@ struct Checker { MPSCQueue global_untyped_queue; + MPSCQueue soa_types_to_complete; }; diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index de83f5058..20e4991e7 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -860,7 +860,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ Entity *f = t->Struct.fields[source_index]; i64 foffset = 0; if (!t->Struct.is_raw_union) { - GB_ASSERT(t->Struct.offsets != nullptr); + GB_ASSERT_MSG(t->Struct.offsets != nullptr, "%s", type_to_string(t)); GB_ASSERT(0 <= f->Variable.field_index && f->Variable.field_index < count); foffset = t->Struct.offsets[source_index]; } diff --git a/src/types.cpp b/src/types.cpp index 6e63f56ed..ebe6271f2 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3772,6 +3772,8 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { return 1; } + type_set_offsets(t); + i64 max = 1; for_array(i, t->Struct.fields) { Type *field_type = t->Struct.fields[i]->type; -- cgit v1.2.3 From 2bdf5f58ef162a74e132e9a2277aaecccca0df4b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 30 Mar 2024 14:23:47 +0000 Subject: Enforce error on old style for/switch l-value --- src/check_expr.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3a275729f..c7a1b460a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2419,10 +2419,6 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { } gb_internal void check_old_for_or_switch_value_usage(Ast *expr) { - if (!(build_context.strict_style || (check_vet_flags(expr) & VetFlag_Style))) { - return; - } - Entity *e = entity_of_node(expr); if (e != nullptr && (e->flags & EntityFlag_OldForOrSwitchValue) != 0) { GB_ASSERT(e->kind == Entity_Variable); -- cgit v1.2.3 From f482cc8374d041795dc106709093f194da5ce5bb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 1 Apr 2024 12:33:56 +0100 Subject: Fix error message --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c7a1b460a..4142968cc 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2428,7 +2428,7 @@ gb_internal void check_old_for_or_switch_value_usage(Ast *expr) { if ((e->flags & EntityFlag_ForValue) != 0) { Type *parent_type = type_deref(e->Variable.for_loop_parent_type); - error(expr, "Assuming a for-in defined value is addressable as the iterable is passed by value has been disallowed with '-strict-style'."); + error(expr, "Assuming a for-in defined value is addressable as the iterable is passed by value has been disallowed."); if (is_type_map(parent_type)) { error_line("\tSuggestion: Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string)); @@ -2438,7 +2438,7 @@ gb_internal void check_old_for_or_switch_value_usage(Ast *expr) { } else { GB_ASSERT((e->flags & EntityFlag_SwitchValue) != 0); - error(expr, "Assuming a switch-in defined value is addressable as the iterable is passed by value has been disallowed with '-strict-style'."); + error(expr, "Assuming a switch-in defined value is addressable as the iterable is passed by value has been disallowed."); error_line("\tSuggestion: Prefer doing 'switch &%.*s in ...'\n", LIT(e->token.string)); } } -- cgit v1.2.3 From bb72ff9c35499078ef5ce22e905ddf919bcc531c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 1 Apr 2024 14:28:11 +0100 Subject: Fix nested `ERROR_BLOCK` bug --- src/check_expr.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4142968cc..c80b08695 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4129,7 +4129,7 @@ gb_internal void update_untyped_expr_value(CheckerContext *c, Ast *e, ExactValue } } -gb_internal void convert_untyped_error(CheckerContext *c, Operand *operand, Type *target_type) { +gb_internal void convert_untyped_error(CheckerContext *c, Operand *operand, Type *target_type, bool ignore_error_block=false) { gbString expr_str = expr_to_string(operand->expr); gbString type_str = type_to_string(target_type); gbString from_type_str = type_to_string(operand->type); @@ -4143,7 +4143,9 @@ gb_internal void convert_untyped_error(CheckerContext *c, Operand *operand, Type } } } - ERROR_BLOCK(); + if (!ignore_error_block) { + begin_error_block(); + } error(operand->expr, "Cannot convert untyped value '%s' to '%s' from '%s'%s", expr_str, type_str, from_type_str, extra_text); if (operand->value.kind == ExactValue_String) { @@ -4158,6 +4160,11 @@ gb_internal void convert_untyped_error(CheckerContext *c, Operand *operand, Type gb_string_free(type_str); gb_string_free(expr_str); operand->mode = Addressing_Invalid; + + if (!ignore_error_block) { + end_error_block(); + } + } gb_internal ExactValue convert_exact_value_for_type(ExactValue v, Type *type) { @@ -4287,7 +4294,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar operand->mode = Addressing_Invalid; ERROR_BLOCK(); - convert_untyped_error(c, operand, target_type); + convert_untyped_error(c, operand, target_type, true); error_line("\tNote: Only a square matrix types can be initialized with a scalar value\n"); return; } else { @@ -4350,7 +4357,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar GB_ASSERT(first_success_index >= 0); operand->mode = Addressing_Invalid; - convert_untyped_error(c, operand, target_type); + convert_untyped_error(c, operand, target_type, true); error_line("Ambiguous type conversion to '%s', which variant did you mean:\n\t", type_str); i32 j = 0; @@ -4375,9 +4382,10 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar ERROR_BLOCK(); operand->mode = Addressing_Invalid; - convert_untyped_error(c, operand, target_type); + convert_untyped_error(c, operand, target_type, true); if (count > 0) { error_line("'%s' is a union which only excepts the following types:\n", type_str); + error_line("\t"); for (i32 i = 0; i < count; i++) { Type *v = t->Union.variants[i]; -- cgit v1.2.3 From 114ddc4a108eff7feb0cd83c7920998ddffd6dd1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 8 Apr 2024 12:06:06 +0100 Subject: Fix printing error when field name could not be found --- src/check_expr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c80b08695..fe8c9599f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4595,7 +4595,8 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v String name = fv->field->Ident.token.string; Selection sub_sel = lookup_field(node->tav.type, name, false); defer (array_free(&sub_sel.index)); - if (sub_sel.index[0] == index) { + if (sub_sel.index.count > 0 && + sub_sel.index[0] == index) { value = fv->value->tav.value; found = true; break; -- cgit v1.2.3 From 810cf22e5ddd772ee214eec306b1ba148623302c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 8 Apr 2024 16:08:35 +0100 Subject: Obfuscate `#file` and `#procedure` when `-obfuscate-source-code-locations` is enabled --- src/check_expr.cpp | 12 ++++++++++-- src/common.cpp | 13 +++++++++++++ src/llvm_backend_const.cpp | 15 ++------------- 3 files changed, 25 insertions(+), 15 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fe8c9599f..7d8e0f829 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8157,8 +8157,12 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A o->mode = Addressing_Constant; String name = bd->name.string; if (name == "file") { + String file = get_file_path_string(bd->token.pos.file_id); + if (build_context.obfuscate_source_code_locations) { + file = obfuscate_string(file, "F"); + } o->type = t_untyped_string; - o->value = exact_value_string(get_file_path_string(bd->token.pos.file_id)); + o->value = exact_value_string(file); } else if (name == "line") { o->type = t_untyped_integer; o->value = exact_value_i64(bd->token.pos.line); @@ -8168,8 +8172,12 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A o->type = t_untyped_string; o->value = exact_value_string(str_lit("")); } else { + String p = c->proc_name; + if (build_context.obfuscate_source_code_locations) { + p = obfuscate_string(p, "P"); + } o->type = t_untyped_string; - o->value = exact_value_string(c->proc_name); + o->value = exact_value_string(p); } } else if (name == "caller_location") { init_core_source_code_location(c->checker); diff --git a/src/common.cpp b/src/common.cpp index aad420325..6a53332d9 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -353,6 +353,19 @@ gb_global bool global_module_path_set = false; #include "thread_pool.cpp" +gb_internal String obfuscate_string(String const &s, char const *prefix) { + if (s.len == 0) { + return {}; + } + GB_ASSERT(prefix != nullptr); + u64 hash = gb_fnv64a(s.text, s.len); + gbString res = gb_string_make(temporary_allocator(), prefix); + res = gb_string_append_fmt(res, "x%llx", cast(long long unsigned)hash); + return make_string_c(res); +} + + + struct StringIntern { StringIntern *next; isize len; diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 1ca5f4965..5b2af1049 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -287,17 +287,6 @@ gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type return lb_const_value(m, t, tv.value); } -gb_internal String lb_obfuscate_string(String const &s, char const *prefix) { - if (s.len == 0) { - return {}; - } - GB_ASSERT(prefix != nullptr); - u64 hash = gb_fnv64a(s.text, s.len); - gbString res = gb_string_make(temporary_allocator(), prefix); - res = gb_string_append_fmt(res, "x%llx", cast(long long unsigned)hash); - return make_string_c(res); -} - gb_internal i32 lb_obfuscate_i32(i32 i) { i32 x = cast(i32)gb_fnv64a(&i, sizeof(i)); if (x < 0) { @@ -314,8 +303,8 @@ gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String cons i32 column = pos.column; if (build_context.obfuscate_source_code_locations) { - file = lb_obfuscate_string(file, "F"); - procedure = lb_obfuscate_string(procedure, "P"); + file = obfuscate_string(file, "F"); + procedure = obfuscate_string(procedure, "P"); line = lb_obfuscate_i32(line); column = lb_obfuscate_i32(column); -- cgit v1.2.3 From ec455046316ba1bf44a6f2118512341a3f68b10c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 8 Apr 2024 16:14:47 +0100 Subject: Obfuscate `#line` --- src/check_expr.cpp | 6 +++++- src/common.cpp | 8 ++++++++ src/llvm_backend_const.cpp | 11 ++--------- 3 files changed, 15 insertions(+), 10 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7d8e0f829..b893b3a00 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8164,8 +8164,12 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A o->type = t_untyped_string; o->value = exact_value_string(file); } else if (name == "line") { + i32 line = bd->token.pos.line; + if (build_context.obfuscate_source_code_locations) { + line = obfuscate_i32(line); + } o->type = t_untyped_integer; - o->value = exact_value_i64(bd->token.pos.line); + o->value = exact_value_i64(line); } else if (name == "procedure") { if (c->curr_proc_decl == nullptr) { error(node, "#procedure may only be used within procedures"); diff --git a/src/common.cpp b/src/common.cpp index 6a53332d9..e0a579c5d 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -364,6 +364,14 @@ gb_internal String obfuscate_string(String const &s, char const *prefix) { return make_string_c(res); } +gb_internal i32 obfuscate_i32(i32 i) { + i32 x = cast(i32)gb_fnv64a(&i, sizeof(i)); + if (x < 0) { + x = 1-x; + } + return cast(i32)x; +} + struct StringIntern { diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 5b2af1049..8035336d3 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -287,13 +287,6 @@ gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type return lb_const_value(m, t, tv.value); } -gb_internal i32 lb_obfuscate_i32(i32 i) { - i32 x = cast(i32)gb_fnv64a(&i, sizeof(i)); - if (x < 0) { - x = 1-x; - } - return cast(i32)x; -} gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String const &procedure_, TokenPos const &pos) { String file = get_file_path_string(pos.file_id); @@ -306,8 +299,8 @@ gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String cons file = obfuscate_string(file, "F"); procedure = obfuscate_string(procedure, "P"); - line = lb_obfuscate_i32(line); - column = lb_obfuscate_i32(column); + line = obfuscate_i32(line); + column = obfuscate_i32(column); } LLVMValueRef fields[4] = {}; -- cgit v1.2.3 From 2b26384b89ed2b29f9d7db13f73c52029a2a2341 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 26 Apr 2024 15:04:46 +0100 Subject: Implement dumb `PtrMap` --- src/check_expr.cpp | 10 +- src/checker.cpp | 5 +- src/exact_value.cpp | 37 +++-- src/ptr_map.cpp | 447 ++++++++++++++++++++++++---------------------------- 4 files changed, 241 insertions(+), 258 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b893b3a00..06d0a8b12 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8079,11 +8079,10 @@ gb_internal void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Op } uintptr key = hash_exact_value(operand.value); - TypeAndToken *found = map_get(seen, key); - if (found != nullptr) { + GB_ASSERT(key != 0); + isize count = multi_map_count(seen, key); + if (count) { TEMPORARY_ALLOCATOR_GUARD(); - - isize count = multi_map_count(seen, key); TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count); multi_map_get_all(seen, key, taps); @@ -9406,7 +9405,8 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * continue; } ExactValue v = f->Constant.value; - auto found = map_get(&seen, hash_exact_value(v)); + uintptr hash = hash_exact_value(v); + auto found = map_get(&seen, hash); if (!found) { array_add(&unhandled, f); } diff --git a/src/checker.cpp b/src/checker.cpp index 3b51cc6e0..64fca0312 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1897,8 +1897,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { add_type_info_dependency(c->info, c->decl, t); MUTEX_GUARD_BLOCK(&c->info->type_info_mutex) { - MapFindResult fr; - auto found = map_try_get(&c->info->type_info_map, t, &fr); + auto found = map_get(&c->info->type_info_map, t); if (found != nullptr) { // Types have already been added return; @@ -1922,7 +1921,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { ti_index = c->info->type_info_types.count; array_add(&c->info->type_info_types, t); } - map_set_internal_from_try_get(&c->checker->info.type_info_map, t, ti_index, fr); + map_set(&c->checker->info.type_info_map, t, ti_index); if (prev) { // NOTE(bill): If a previous one exists already, no need to continue diff --git a/src/exact_value.cpp b/src/exact_value.cpp index b744d2db0..83af82f55 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -54,37 +54,50 @@ gb_global ExactValue const empty_exact_value = {}; gb_internal uintptr hash_exact_value(ExactValue v) { mutex_lock(&hash_exact_value_mutex); defer (mutex_unlock(&hash_exact_value_mutex)); + + uintptr res = 0; switch (v.kind) { case ExactValue_Invalid: return 0; case ExactValue_Bool: - return gb_fnv32a(&v.value_bool, gb_size_of(v.value_bool)); + res = gb_fnv32a(&v.value_bool, gb_size_of(v.value_bool)); + break; case ExactValue_String: - return gb_fnv32a(v.value_string.text, v.value_string.len); + res = gb_fnv32a(v.value_string.text, v.value_string.len); + break; case ExactValue_Integer: { u32 key = gb_fnv32a(v.value_integer.dp, gb_size_of(*v.value_integer.dp) * v.value_integer.used); u8 last = (u8)v.value_integer.sign; - return (key ^ last) * 0x01000193; + res = (key ^ last) * 0x01000193; + break; } case ExactValue_Float: - return gb_fnv32a(&v.value_float, gb_size_of(v.value_float)); + res = gb_fnv32a(&v.value_float, gb_size_of(v.value_float)); + break; case ExactValue_Pointer: - return ptr_map_hash_key(v.value_pointer); + res = ptr_map_hash_key(v.value_pointer); + break; case ExactValue_Complex: - return gb_fnv32a(v.value_complex, gb_size_of(Complex128)); + res = gb_fnv32a(v.value_complex, gb_size_of(Complex128)); + break; case ExactValue_Quaternion: - return gb_fnv32a(v.value_quaternion, gb_size_of(Quaternion256)); + res = gb_fnv32a(v.value_quaternion, gb_size_of(Quaternion256)); + break; case ExactValue_Compound: - return ptr_map_hash_key(v.value_compound); + res = ptr_map_hash_key(v.value_compound); + break; case ExactValue_Procedure: - return ptr_map_hash_key(v.value_procedure); + res = ptr_map_hash_key(v.value_procedure); + break; case ExactValue_Typeid: - return ptr_map_hash_key(v.value_typeid); + res = ptr_map_hash_key(v.value_typeid); + break; + default: + res = gb_fnv32a(&v, gb_size_of(ExactValue)); } - return gb_fnv32a(&v, gb_size_of(ExactValue)); - + return res & 0x7fffffff; } diff --git a/src/ptr_map.cpp b/src/ptr_map.cpp index 23278014f..8fd627768 100644 --- a/src/ptr_map.cpp +++ b/src/ptr_map.cpp @@ -16,23 +16,21 @@ struct MapFindResult { }; enum : MapIndex { MAP_SENTINEL = ~(MapIndex)0 }; +static void *const MAP_TOMBSTONE = (void *)~(uintptr)0; template struct PtrMapEntry { static_assert(sizeof(K) == sizeof(void *), "Key size must be pointer size"); - K key; - V value; - MapIndex next; + K key; + V value; }; template struct PtrMap { - MapIndex * hashes; - usize hashes_count; PtrMapEntry *entries; u32 count; - u32 entries_capacity; + u32 capacity; }; @@ -69,7 +67,6 @@ template gb_internal void map_grow (PtrMap< template gb_internal void map_rehash (PtrMap *h, isize new_count); template gb_internal void map_reserve (PtrMap *h, isize cap); -#if PTR_MAP_ENABLE_MULTI_MAP // Mutlivalued map procedure template gb_internal PtrMapEntry * multi_map_find_first(PtrMap *h, K key); template gb_internal PtrMapEntry * multi_map_find_next (PtrMap *h, PtrMapEntry *e); @@ -79,7 +76,6 @@ template gb_internal void multi_map_get_all (PtrMap< template gb_internal void multi_map_insert (PtrMap *h, K key, V const &value); template gb_internal void multi_map_remove (PtrMap *h, K key, PtrMapEntry *e); template gb_internal void multi_map_remove_all(PtrMap *h, K key); -#endif gb_internal gbAllocator map_allocator(void) { return heap_allocator(); @@ -94,170 +90,141 @@ gb_internal gb_inline void map_init(PtrMap *h, isize capacity) { template gb_internal gb_inline void map_destroy(PtrMap *h) { gbAllocator a = map_allocator(); - gb_free(a, h->hashes); gb_free(a, h->entries); } -template -gb_internal void map__resize_hashes(PtrMap *h, usize count) { - h->hashes_count = cast(u32)resize_array_raw(&h->hashes, map_allocator(), h->hashes_count, count, MAP_CACHE_LINE_SIZE); -} - -template -gb_internal void map__reserve_entries(PtrMap *h, usize capacity) { - h->entries_capacity = cast(u32)resize_array_raw(&h->entries, map_allocator(), h->entries_capacity, capacity, MAP_CACHE_LINE_SIZE); -} - template -gb_internal MapIndex map__add_entry(PtrMap *h, K key) { - PtrMapEntry e = {}; - e.key = key; - e.next = MAP_SENTINEL; - if (h->count+1 >= h->entries_capacity) { - map__reserve_entries(h, gb_max(h->entries_capacity*2, 4)); - } - h->entries[h->count++] = e; - return cast(MapIndex)(h->count-1); -} - -template -gb_internal MapFindResult map__find(PtrMap *h, K key) { - MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}; - if (h->hashes_count == 0) { - return fr; +gb_internal void map__insert(PtrMap *h, K key, V const &value) { + if (h->count+1 >= h->capacity) { + map_grow(h); } u32 hash = ptr_map_hash_key(key); - fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1)); - fr.entry_index = h->hashes[fr.hash_index]; - while (fr.entry_index != MAP_SENTINEL) { - auto *entry = &h->entries[fr.entry_index]; - if (entry->key == key) { - return fr; + u32 mask = h->capacity-1; + MapIndex index = hash & mask; + MapIndex original_index = index; + do { + auto *entry = h->entries+index; + if (!entry->key || entry->key == cast(K)MAP_TOMBSTONE) { + entry->key = key; + entry->value = value; + h->count += 1; + return; } - fr.entry_prev = fr.entry_index; - fr.entry_index = entry->next; - } - return fr; -} + index = (index+1)&mask; + } while (index != original_index); -template -gb_internal MapFindResult map__find_from_entry(PtrMap *h, PtrMapEntry *e) { - MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}; - if (h->hashes_count == 0) { - return fr; - } - u32 hash = ptr_map_hash_key(e->key); - fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1)); - fr.entry_index = h->hashes[fr.hash_index]; - while (fr.entry_index != MAP_SENTINEL) { - if (&h->entries[fr.entry_index] == e) { - return fr; - } - fr.entry_prev = fr.entry_index; - fr.entry_index = h->entries[fr.entry_index].next; - } - return fr; + GB_PANIC("FAILED TO INSERT"); } template gb_internal b32 map__full(PtrMap *h) { - return 0.75f * h->hashes_count <= h->count; + return 0.75f * h->capacity <= h->count; } template gb_internal gb_inline void map_grow(PtrMap *h) { - isize new_count = gb_max(h->hashes_count<<1, 16); - map_rehash(h, new_count); + isize new_capacity = gb_max(h->capacity<<1, 16); + map_reserve(h, new_capacity); } template -gb_internal void map_reset_entries(PtrMap *h) { - for (usize i = 0; i < h->hashes_count; i++) { - h->hashes[i] = MAP_SENTINEL; - } - for (usize i = 0; i < h->count; i++) { - MapFindResult fr; - PtrMapEntry *e = &h->entries[i]; - e->next = MAP_SENTINEL; - fr = map__find_from_entry(h, e); - if (fr.entry_prev == MAP_SENTINEL) { - h->hashes[fr.hash_index] = cast(MapIndex)i; - } else { - h->entries[fr.entry_prev].next = cast(MapIndex)i; - } +gb_internal void try_map_grow(PtrMap *h) { + if (h->capacity == 0 || map__full(h)) { + map_grow(h); } } + template gb_internal void map_reserve(PtrMap *h, isize cap) { - if (h->count*2 < h->hashes_count) { + if (cap < h->capacity) { return; } - map__reserve_entries(h, cap); - map__resize_hashes(h, cap*2); - map_reset_entries(h); -} + cap = next_pow2_isize(cap); + typedef PtrMapEntry EntryType; + PtrMap new_h = {}; + new_h.count = 0; + new_h.capacity = cast(u32)cap; + new_h.entries = gb_alloc_array(string_map_allocator(), EntryType, new_h.capacity); -template -gb_internal void map_rehash(PtrMap *h, isize new_count) { - map_reserve(h, new_count); + if (h->count) { + for (u32 i = 0; i < h->capacity; i++) { + auto *entry = h->entries+i; + if (entry->key && + entry->key != cast(K)MAP_TOMBSTONE) { + map__insert(&new_h, entry->key, entry->value); + } + } + } + map_destroy(h); + *h = new_h; } template gb_internal V *map_get(PtrMap *h, K key) { - MapIndex hash_index = MAP_SENTINEL; - MapIndex entry_prev = MAP_SENTINEL; - MapIndex entry_index = MAP_SENTINEL; - if (h->hashes_count != 0) { - u32 hash = ptr_map_hash_key(key); - hash_index = cast(MapIndex)(hash & (h->hashes_count-1)); - entry_index = h->hashes[hash_index]; - while (entry_index != MAP_SENTINEL) { - auto *entry = &h->entries[entry_index]; - if (entry->key == key) { - return &entry->value; - } - entry_prev = entry_index; - entry_index = entry->next; - } + if (h->count == 0) { + return nullptr; + } + if (key == 0) { + GB_PANIC("0 key"); } + + u32 hash = ptr_map_hash_key(key); + u32 mask = (h->capacity-1); + u32 index = hash & mask; + u32 original_index = index; + do { + auto *entry = h->entries+index; + if (!entry->key) { + // NOTE(bill): no found, but there isn't any key removal for this hash map + return nullptr; + } else if (entry->key == key) { + return &entry->value; + } + index = (index+1) & mask; + } while (original_index != index); return nullptr; } template -gb_internal V *map_try_get(PtrMap *h, K key, MapFindResult *fr_) { - MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}; - if (h->hashes_count != 0) { - u32 hash = ptr_map_hash_key(key); - fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1)); - fr.entry_index = h->hashes[fr.hash_index]; - while (fr.entry_index != MAP_SENTINEL) { - auto *entry = &h->entries[fr.entry_index]; - if (entry->key == key) { - return &entry->value; - } - fr.entry_prev = fr.entry_index; - fr.entry_index = entry->next; - } +gb_internal V *map_try_get(PtrMap *h, K key, MapIndex *found_index_) { + if (found_index_) *found_index_ = ~(MapIndex)0; + + if (h->count == 0) { + return nullptr; } - if (h->hashes_count == 0 || map__full(h)) { - map_grow(h); + if (key == 0) { + GB_PANIC("0 key"); } - if (fr_) *fr_ = fr; + + u32 hash = ptr_map_hash_key(key); + u32 mask = (h->capacity-1); + u32 index = hash & mask; + u32 original_index = index; + do { + auto *entry = h->entries+index; + if (!entry->key) { + // NOTE(bill): no found, but there isn't any key removal for this hash map + return nullptr; + } else if (entry->key == key) { + if (found_index_) *found_index_ = index; + return &entry->value; + } + index = (index+1) & mask; + } while (original_index != index); return nullptr; } template -gb_internal void map_set_internal_from_try_get(PtrMap *h, K key, V const &value, MapFindResult const &fr) { - MapIndex index = map__add_entry(h, key); - if (fr.entry_prev != MAP_SENTINEL) { - h->entries[fr.entry_prev].next = index; +gb_internal void map_set_internal_from_try_get(PtrMap *h, K key, V const &value, MapIndex found_index) { + if (found_index != MAP_SENTINEL) { + GB_ASSERT(h->entries[found_index].key == key); + h->entries[found_index].value = value; } else { - h->hashes[fr.hash_index] = index; + map_set(h, key, value); } - h->entries[index].value = value; } template @@ -269,116 +236,83 @@ gb_internal V &map_must_get(PtrMap *h, K key) { template gb_internal void map_set(PtrMap *h, K key, V const &value) { - MapIndex index; - MapFindResult fr; - if (h->hashes_count == 0) { - map_grow(h); - } - fr = map__find(h, key); - if (fr.entry_index != MAP_SENTINEL) { - index = fr.entry_index; - } else { - index = map__add_entry(h, key); - if (fr.entry_prev != MAP_SENTINEL) { - h->entries[fr.entry_prev].next = index; - } else { - h->hashes[fr.hash_index] = index; - } - } - h->entries[index].value = value; - - if (map__full(h)) { - map_grow(h); + GB_ASSERT(key != 0); + try_map_grow(h); + auto *found = map_get(h, key); + if (found) { + *found = value; + return; } + map__insert(h, key, value); } // returns true if it previously existed template gb_internal bool map_set_if_not_previously_exists(PtrMap *h, K key, V const &value) { - MapIndex index; - MapFindResult fr; - if (h->hashes_count == 0) { - map_grow(h); - } - fr = map__find(h, key); - if (fr.entry_index != MAP_SENTINEL) { + try_map_grow(h); + auto *found = map_get(h, key); + if (found) { return true; - } else { - index = map__add_entry(h, key); - if (fr.entry_prev != MAP_SENTINEL) { - h->entries[fr.entry_prev].next = index; - } else { - h->hashes[fr.hash_index] = index; - } - } - h->entries[index].value = value; - - if (map__full(h)) { - map_grow(h); } + map__insert(h, key, value); return false; } -template -gb_internal void map__erase(PtrMap *h, MapFindResult const &fr) { - MapFindResult last; - if (fr.entry_prev == MAP_SENTINEL) { - h->hashes[fr.hash_index] = h->entries[fr.entry_index].next; - } else { - h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next; - } - if (fr.entry_index == h->count-1) { - h->count--; - return; - } - h->entries[fr.entry_index] = h->entries[h->count-1]; - h->count--; - - last = map__find(h, h->entries[fr.entry_index].key); - if (last.entry_prev != MAP_SENTINEL) { - h->entries[last.entry_prev].next = fr.entry_index; - } else { - h->hashes[last.hash_index] = fr.entry_index; - } -} - template gb_internal void map_remove(PtrMap *h, K key) { - MapFindResult fr = map__find(h, key); - if (fr.entry_index != MAP_SENTINEL) { - map__erase(h, fr); + MapIndex found_index = 0; + if (map_try_get(h, key, &found_index)) { + h->entries[found_index].key = cast(K)MAP_TOMBSTONE; + h->count -= 1; } } template gb_internal gb_inline void map_clear(PtrMap *h) { h->count = 0; - for (usize i = 0; i < h->hashes_count; i++) { - h->hashes[i] = MAP_SENTINEL; - } + gb_zero_array(h->entries, h->capacity); } #if PTR_MAP_ENABLE_MULTI_MAP template gb_internal PtrMapEntry *multi_map_find_first(PtrMap *h, K key) { - MapIndex i = map__find(h, key).entry_index; - if (i == MAP_SENTINEL) { + if (h->count == 0) { return nullptr; } - return &h->entries[i]; + u32 hash = ptr_map_hash_key(key); + u32 mask = (h->capacity-1); + u32 index = hash & mask; + u32 original_index = index; + do { + auto *entry = h->entries+index; + if (!entry->key) { + // NOTE(bill): no found, but there isn't any key removal for this hash map + return nullptr; + } else if (entry->key == key) { + return entry; + } + index = (index+1) & mask; + } while (original_index != index); + return nullptr; } template gb_internal PtrMapEntry *multi_map_find_next(PtrMap *h, PtrMapEntry *e) { - MapIndex i = e->next; - while (i != MAP_SENTINEL) { - if (h->entries[i].key == e->key) { - return &h->entries[i]; + u32 mask = h->capacity-1; + MapIndex index = cast(MapIndex)(e - h->entries); + MapIndex original_index = index; + do { + index = (index+1)&mask; + auto *entry = h->entries+index; + if (!entry->key) { + return nullptr; } - i = h->entries[i].next; - } + if (entry->key == e->key) { + return entry; + } + } while (original_index != index); return nullptr; } @@ -405,34 +339,16 @@ gb_internal void multi_map_get_all(PtrMap *h, K key, V *items) { template gb_internal void multi_map_insert(PtrMap *h, K key, V const &value) { - MapFindResult fr; - MapIndex i; - if (h->hashes_count == 0) { - map_grow(h); - } - // Make - fr = map__find(h, key); - i = map__add_entry(h, key); - if (fr.entry_prev == MAP_SENTINEL) { - h->hashes[fr.hash_index] = i; - } else { - h->entries[fr.entry_prev].next = i; - } - h->entries[i].next = fr.entry_index; - h->entries[i].value = value; - // Grow if needed - if (map__full(h)) { - map_grow(h); - } + try_map_grow(h); + map__insert(h, key, value); } -template -gb_internal void multi_map_remove(PtrMap *h, K key, PtrMapEntry *e) { - MapFindResult fr = map__find_from_entry(h, e); - if (fr.entry_index != MAP_SENTINEL) { - map__erase(h, fr); - } -} +// template +// gb_internal void multi_map_remove(PtrMap *h, K key, PtrMapEntry *e) { +// if (fr.entry_index != MAP_SENTINEL) { +// map__erase(h, fr); +// } +// } template gb_internal void multi_map_remove_all(PtrMap *h, K key) { @@ -443,22 +359,77 @@ gb_internal void multi_map_remove_all(PtrMap *h, K key) { #endif + + +template +struct PtrMapIterator { + PtrMap *map; + MapIndex index; + + PtrMapIterator &operator++() noexcept { + for (;;) { + ++index; + if (map->capacity == index) { + return *this; + } + PtrMapEntry *entry = map->entries+index; + if (entry->key && entry->key != cast(K)MAP_TOMBSTONE) { + return *this; + } + } + } + + bool operator==(PtrMapIterator const &other) const noexcept { + return this->map == other->map && this->index == other->index; + } + + operator PtrMapEntry *() const { + return map->entries+index; + } +}; + + template -gb_internal PtrMapEntry *begin(PtrMap &m) { - return m.entries; +gb_internal PtrMapIterator end(PtrMap &m) noexcept { + return PtrMapIterator{&m, m.capacity}; } + template -gb_internal PtrMapEntry const *begin(PtrMap const &m) { - return m.entries; +gb_internal PtrMapIterator const end(PtrMap const &m) noexcept { + return PtrMapIterator{&m, m.capacity}; } + template -gb_internal PtrMapEntry *end(PtrMap &m) { - return m.entries + m.count; -} +gb_internal PtrMapIterator begin(PtrMap &m) noexcept { + if (m.count == 0) { + return end(m); + } + MapIndex index = 0; + while (index < m.capacity) { + auto key = m.entries[index].key; + if (key && key != cast(K)MAP_TOMBSTONE) { + break; + } + index++; + } + return PtrMapIterator{&m, index}; +} template -gb_internal PtrMapEntry const *end(PtrMap const &m) { - return m.entries + m.count; +gb_internal PtrMapIterator const begin(PtrMap const &m) noexcept { + if (m.count == 0) { + return end(m); + } + + MapIndex index = 0; + while (index < m.capacity) { + auto key = m.entries[index].key; + if (key && key != cast(K)MAP_TOMBSTONE) { + break; + } + index++; + } + return PtrMapIterator{&m, index}; } -- 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_expr.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 f2505b096d7367e4a6aa66475cda81e9f9bc0dae Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 3 May 2024 14:22:30 +0100 Subject: Improve error message's suggestion for `if !integer` --- src/check_expr.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 06d0a8b12..83706112b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1802,11 +1802,13 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) { case Token_Not: if (!is_type_boolean(type) || is_type_array_like(o->type)) { ERROR_BLOCK(); - str = expr_to_string(o->expr); error(op, "Operator '%.*s' is only allowed on boolean expressions", LIT(op.string)); - gb_string_free(str); if (is_type_integer(type)) { - error_line("\tSuggestion: Did you mean to use the bitwise not operator '~'?\n"); + str = expr_to_string(o->expr); + error_line("\tSuggestion: Did you mean to do one of the following?\n"); + error_line("\t\t'%s == 0'?\n", str); + error_line("\t\tUse of the bitwise not operator '~'?\n"); + gb_string_free(str); } } else { o->type = t_untyped_bool; -- cgit v1.2.3 From 8e4f9cb777b91ade22fc1f00d166af1ea06624c5 Mon Sep 17 00:00:00 2001 From: Victor Sohier <1sohiervic@gmail.com> Date: Sun, 5 May 2024 21:08:33 -0400 Subject: Fix: Fixed #soa arrays --- src/check_expr.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c143cfce0..939466a64 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -102,6 +102,7 @@ gb_internal Type * check_init_variable (CheckerContext *c, Entity * gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type, i64 max_bit_size=0); gb_internal void add_map_key_type_dependencies(CheckerContext *ctx, Type *key); +gb_internal Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type); gb_internal Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem); gb_internal Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem); @@ -1409,11 +1410,19 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T poly->Struct.soa_kind != StructSoa_None) { bool ok = is_polymorphic_type_assignable(c, poly->Struct.soa_elem, source->Struct.soa_elem, true, modify_type); if (ok) switch (source->Struct.soa_kind) { - case StructSoa_Fixed: default: GB_PANIC("Unhandled SOA Kind"); break; - + case StructSoa_Fixed: + if (modify_type) { + bool breakpoint = true; + Type *type = make_soa_struct_fixed( + c, nullptr, poly->Struct.node, + poly->Struct.soa_elem, poly->Struct.soa_count, + nullptr); + gb_memmove(poly, type, gb_size_of(*type)); + } + break; case StructSoa_Slice: if (modify_type) { Type *type = make_soa_struct_slice(c, nullptr, poly->Struct.node, poly->Struct.soa_elem); -- cgit v1.2.3 From a9b18c1ec02e6bf0db337accf3edcd9fa7984250 Mon Sep 17 00:00:00 2001 From: Victor Sohier <1sohiervic@gmail.com> Date: Sun, 5 May 2024 21:15:41 -0400 Subject: Formatting --- src/check_expr.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 939466a64..c11021a4f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1416,10 +1416,7 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T case StructSoa_Fixed: if (modify_type) { bool breakpoint = true; - Type *type = make_soa_struct_fixed( - c, nullptr, poly->Struct.node, - poly->Struct.soa_elem, poly->Struct.soa_count, - nullptr); + Type *type = make_soa_struct_fixed(c, nullptr, poly->Struct.node, poly->Struct.soa_elem, poly->Struct.soa_count, nullptr); gb_memmove(poly, type, gb_size_of(*type)); } break; -- cgit v1.2.3 From 6cb0f5d8c5aa71acf28870afe10295e939a8979d Mon Sep 17 00:00:00 2001 From: Victor Sohier <1sohiervic@gmail.com> Date: Mon, 6 May 2024 18:04:35 -0400 Subject: Explicitly handle previously implicitly handled case --- src/check_expr.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c11021a4f..04464d09f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1410,6 +1410,7 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T poly->Struct.soa_kind != StructSoa_None) { bool ok = is_polymorphic_type_assignable(c, poly->Struct.soa_elem, source->Struct.soa_elem, true, modify_type); if (ok) switch (source->Struct.soa_kind) { + case StructSoa_None: default: GB_PANIC("Unhandled SOA Kind"); break; -- cgit v1.2.3 From 56b62996c35ac364f545c034cd731e808b35da20 Mon Sep 17 00:00:00 2001 From: Victor Sohier <1sohiervic@gmail.com> Date: Mon, 6 May 2024 18:20:20 -0400 Subject: Remove breakpoint hook --- src/check_expr.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 04464d09f..013638e63 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1416,7 +1416,6 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T break; case StructSoa_Fixed: if (modify_type) { - bool breakpoint = true; Type *type = make_soa_struct_fixed(c, nullptr, poly->Struct.node, poly->Struct.soa_elem, poly->Struct.soa_count, nullptr); gb_memmove(poly, type, gb_size_of(*type)); } -- cgit v1.2.3 From f54977336b27c32eab52b77d94e7b1610f4350cf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 9 May 2024 15:56:00 +0100 Subject: With `-vet-style`, give suggestion of separating where clauses with a comma rather than '&&' This improves the error messages --- src/check_expr.cpp | 14 ++++++++++++++ src/check_type.cpp | 2 +- src/parser.cpp | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 013638e63..98aebfe4e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6193,6 +6193,20 @@ gb_internal bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Sco } return false; } + + if (ast_file_vet_style(ctx->file)) { + Ast *c = unparen_expr(clause); + if (c->kind == Ast_BinaryExpr && c->BinaryExpr.op.kind == Token_CmpAnd) { + ERROR_BLOCK(); + error(c, "Prefer to separate 'where' clauses with a comma rather than '&&'"); + gbString x = expr_to_string(c->BinaryExpr.left); + gbString y = expr_to_string(c->BinaryExpr.right); + error_line("\tSuggestion: '%s, %s'", x, y); + gb_string_free(y); + gb_string_free(x); + } + } + } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 3d11b5012..11e332757 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1166,7 +1166,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, } } if (all_ones && all_booleans) { - if (build_context.vet_flags & VetFlag_Style) { + if (ast_file_vet_style(ctx->file)) { char const *msg = "This 'bit_field' is better expressed as a 'bit_set' since all of the fields are booleans, of 1-bit in size, and the backing type is an integer (-vet-style)"; error(node, msg); } else { diff --git a/src/parser.cpp b/src/parser.cpp index 04505cbd7..6e859fe32 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,7 +1,7 @@ #include "parser_pos.cpp" gb_internal u64 ast_file_vet_flags(AstFile *f) { - if (f->vet_flags_set) { + if (f != nullptr && f->vet_flags_set) { return f->vet_flags; } return build_context.vet_flags; -- cgit v1.2.3 From 98827c867dd88b1a72d74f0a6d703f7a25d81d91 Mon Sep 17 00:00:00 2001 From: Laytan Date: Thu, 9 May 2024 19:21:39 +0200 Subject: fix duplicate suggestions and add missing newline --- src/check_expr.cpp | 2 +- src/error.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 98aebfe4e..f0c33d9d8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6201,7 +6201,7 @@ gb_internal bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Sco error(c, "Prefer to separate 'where' clauses with a comma rather than '&&'"); gbString x = expr_to_string(c->BinaryExpr.left); gbString y = expr_to_string(c->BinaryExpr.right); - error_line("\tSuggestion: '%s, %s'", x, y); + error_line("\tSuggestion: '%s, %s'\n", x, y); gb_string_free(y); gb_string_free(x); } diff --git a/src/error.cpp b/src/error.cpp index 1877a672b..688d1b34a 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -719,9 +719,13 @@ gb_internal void print_all_errors(void) { } } - if (it.str.len-it.pos > 0) { - array_add_elems(&prev_ev->msg, it.str.text+it.pos, it.str.len-it.pos); + // Merge additional text (suggestions for example) into the previous error. + String current = {prev_ev->msg.data, prev_ev->msg.count}; + String addition = {it.str.text+it.pos, it.str.len-it.pos}; + if (addition.len > 0 && !string_contains_string(current, addition)) { + array_add_elems(&prev_ev->msg, addition.text, addition.len); } + array_free(&ev.msg); array_ordered_remove(&global_error_collector.error_values, i); } else { -- cgit v1.2.3 From 0f76c22c463f678f8e681e754c8fe0acf718546c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 12 May 2024 17:48:06 +0100 Subject: Check for illegal use of `distinct` --- src/check_expr.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f0c33d9d8..08f488642 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -10788,6 +10788,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast return Expr_Expr; case_end; + case Ast_DistinctType: case Ast_TypeidType: case Ast_PolyType: case Ast_ProcType: -- cgit v1.2.3 From facae34354dad8a00caddfb7d224774d9d768414 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 13 May 2024 11:53:59 +0100 Subject: Fix #3584 --- src/check_expr.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 08f488642..4618bf969 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1441,6 +1441,13 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T // return check_is_assignable_to(c, &o, poly); // && is_type_subtype_of_and_allow_polymorphic(o.type, poly); } return false; + + case Type_BitField: + if (source->kind == Type_BitField) { + return is_polymorphic_type_assignable(c, poly->BitField.backing_type, source->BitField.backing_type, true, modify_type); + } + return false; + case Type_Tuple: GB_PANIC("This should never happen"); return false; -- cgit v1.2.3 From d1217340f57168311cf26311f4d75a94fb26323b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 13 May 2024 12:26:01 +0100 Subject: Fix #3573 --- src/check_expr.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4618bf969..1fc6eeb52 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1794,6 +1794,13 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) { gb_string_free(str); return false; } + if (o->mode == Addressing_Type) { + gbString str = type_to_string(o->type); + error(o->expr, "Expected an expression for operator '%.*s', got type '%s'", LIT(op.string), str); + gb_string_free(str); + return false; + } + Type *type = base_type(core_array_type(o->type)); gbString str = nullptr; switch (op.kind) { -- cgit v1.2.3 From 8d687a959d29c0ef0c631103b9775091e37c7e81 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 13 May 2024 12:52:28 +0100 Subject: Fix #3516 --- src/check_expr.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 1fc6eeb52..6a293a97e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -10263,6 +10263,17 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, case Type_Struct: if (is_type_soa_struct(t)) { valid = true; + if (t->Struct.soa_kind == StructSoa_Fixed) { + max_count = t->Struct.soa_count; + if (o->mode != Addressing_Variable && !is_type_pointer(o->type)) { + gbString str = expr_to_string(node); + error(node, "Cannot slice #soa array '%s', value is not addressable", str); + gb_string_free(str); + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } + } o->type = make_soa_struct_slice(c, nullptr, nullptr, t->Struct.soa_elem); } break; -- cgit v1.2.3 From a344bc4c0e672d9740f5777dae862723fe269973 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 16 May 2024 14:39:16 +0100 Subject: Remove the old switch/for semantics entirely and enforce `switch &x in y` --- src/check_expr.cpp | 46 +++++++++++++--------------------------------- src/check_stmt.cpp | 30 ++---------------------------- src/entity.cpp | 2 -- 3 files changed, 15 insertions(+), 63 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6a293a97e..c44232dab 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2440,32 +2440,6 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable; } -gb_internal void check_old_for_or_switch_value_usage(Ast *expr) { - Entity *e = entity_of_node(expr); - if (e != nullptr && (e->flags & EntityFlag_OldForOrSwitchValue) != 0) { - GB_ASSERT(e->kind == Entity_Variable); - - ERROR_BLOCK(); - - if ((e->flags & EntityFlag_ForValue) != 0) { - Type *parent_type = type_deref(e->Variable.for_loop_parent_type); - - error(expr, "Assuming a for-in defined value is addressable as the iterable is passed by value has been disallowed."); - - if (is_type_map(parent_type)) { - error_line("\tSuggestion: Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string)); - } else { - error_line("\tSuggestion: Prefer doing 'for &%.*s in ...'\n", LIT(e->token.string)); - } - } else { - GB_ASSERT((e->flags & EntityFlag_SwitchValue) != 0); - - error(expr, "Assuming a switch-in defined value is addressable as the iterable is passed by value has been disallowed."); - error_line("\tSuggestion: Prefer doing 'switch &%.*s in ...'\n", LIT(e->token.string)); - } - } -} - gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { switch (op.kind) { case Token_And: { // Pointer address @@ -2493,7 +2467,10 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * { ERROR_BLOCK(); error(op, "Cannot take the pointer address of '%s'", str); - if (e != nullptr && (e->flags & EntityFlag_ForValue) != 0) { + if (e == nullptr) { + break; + } + if ((e->flags & EntityFlag_ForValue) != 0) { Type *parent_type = type_deref(e->Variable.for_loop_parent_type); if (parent_type != nullptr && is_type_string(parent_type)) { @@ -2503,9 +2480,17 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * } else { error_line("\tSuggestion: Did you want to pass the iterable value to the for statement by pointer to get addressable semantics?\n"); } + + if (is_type_map(parent_type)) { + error_line("\t Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string)); + } else { + error_line("\t Prefer doing 'for &%.*s in ...'\n", LIT(e->token.string)); + } } - if (e != nullptr && (e->flags & EntityFlag_SwitchValue) != 0) { + if ((e->flags & EntityFlag_SwitchValue) != 0) { error_line("\tSuggestion: Did you want to pass the value to the switch statement by pointer to get addressable semantics?\n"); + + error_line("\t Prefer doing 'switch &%.*s in ...'\n", LIT(e->token.string)); } } break; @@ -2527,11 +2512,6 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * o->type = alloc_type_pointer(o->type); } } else { - if (ast_node_expect(node, Ast_UnaryExpr)) { - ast_node(ue, UnaryExpr, node); - check_old_for_or_switch_value_usage(ue->expr); - } - o->type = alloc_type_pointer(o->type); } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 875503874..0267bdf80 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -501,7 +501,6 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O return nullptr; case Addressing_Variable: - check_old_for_or_switch_value_usage(lhs->expr); break; case Addressing_MapIndex: { @@ -523,9 +522,8 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O break; } - case Addressing_Context: { + case Addressing_Context: break; - } case Addressing_SoaVariable: break; @@ -1328,7 +1326,6 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ } } - bool is_ptr = is_type_pointer(x.type); // NOTE(bill): Check for multiple defaults Ast *first_default = nullptr; @@ -1447,15 +1444,6 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ } bool is_reference = is_addressed; - bool old_style = false; - - if (!is_reference && - is_ptr && - cc->list.count == 1 && - case_type != nullptr) { - is_reference = true; - old_style = true; - } if (cc->list.count > 1 || saw_nil) { case_type = nullptr; @@ -1477,9 +1465,6 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ if (!is_reference) { tag_var->flags |= EntityFlag_Value; } - if (old_style) { - tag_var->flags |= EntityFlag_OldForOrSwitchValue; - } add_entity(ctx, ctx->scope, lhs, tag_var); add_entity_use(ctx, lhs, tag_var); add_implicit_entity(ctx, stmt, tag_var); @@ -1618,7 +1603,6 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) auto entities = array_make(temporary_allocator(), 0, 2); bool is_map = false; bool is_bit_set = false; - bool use_by_reference_for_value = false; bool is_soa = false; bool is_reverse = rs->reverse; @@ -1679,7 +1663,6 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } } } - bool is_ptr = is_type_pointer(operand.type); Type *t = base_type(type_deref(operand.type)); switch (t->kind) { @@ -1719,32 +1702,27 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) break; case Type_EnumeratedArray: - if (is_ptr) use_by_reference_for_value = true; array_add(&vals, t->EnumeratedArray.elem); array_add(&vals, t->EnumeratedArray.index); break; case Type_Array: - if (is_ptr) use_by_reference_for_value = true; - if (!is_ptr) is_possibly_addressable = operand.mode == Addressing_Variable; + is_possibly_addressable = operand.mode == Addressing_Variable; array_add(&vals, t->Array.elem); array_add(&vals, t_int); break; case Type_DynamicArray: - if (is_ptr) use_by_reference_for_value = true; array_add(&vals, t->DynamicArray.elem); array_add(&vals, t_int); break; case Type_Slice: - if (is_ptr) use_by_reference_for_value = true; array_add(&vals, t->Slice.elem); array_add(&vals, t_int); break; case Type_Map: - if (is_ptr) use_by_reference_for_value = true; is_map = true; array_add(&vals, t->Map.key); array_add(&vals, t->Map.value); @@ -1817,7 +1795,6 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) case Type_Struct: if (t->Struct.soa_kind != StructSoa_None) { is_soa = true; - if (is_ptr) use_by_reference_for_value = true; array_add(&vals, t->Struct.soa_elem); array_add(&vals, t_int); } @@ -1894,9 +1871,6 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) char const *idx_name = is_map ? "key" : is_bit_set ? "element" : "index"; error(token, "The %s variable '%.*s' cannot be made addressable", idx_name, LIT(str)); } - } else if (i == addressable_index && use_by_reference_for_value) { - entity->flags |= EntityFlag_OldForOrSwitchValue; - entity->flags &= ~EntityFlag_Value; } if (is_soa) { if (i == 0) { diff --git a/src/entity.cpp b/src/entity.cpp index 60ca208ec..8a7417006 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -85,8 +85,6 @@ enum EntityFlag : u64 { EntityFlag_Require = 1ull<<50, EntityFlag_ByPtr = 1ull<<51, // enforce parameter is passed by pointer - EntityFlag_OldForOrSwitchValue = 1ull<<52, - EntityFlag_Overridden = 1ull<<63, }; -- cgit v1.2.3 From 32245e93a106c5cb1ee9b448789f623a4dbef717 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 16 May 2024 16:18:21 +0100 Subject: Fix #3514 along with `soa.a[i]` bounds checking --- src/check_expr.cpp | 4 ++-- src/check_type.cpp | 15 ++++++++++--- src/llvm_backend_expr.cpp | 50 +++++++++++++++++++++++++++++++------------- src/llvm_backend_general.cpp | 2 +- 4 files changed, 50 insertions(+), 21 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c44232dab..c9cfb58be 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7806,8 +7806,8 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 if (is_type_pointer(original_type) && indirection) { Type *ptr = base_type(original_type); - if (ptr->kind == Type_Pointer && o->mode == Addressing_SoaVariable) { - o->type = ptr->Pointer.elem; + if (ptr->kind == Type_MultiPointer && o->mode == Addressing_SoaVariable) { + o->type = ptr->MultiPointer.elem; o->mode = Addressing_Value; return true; } diff --git a/src/check_type.cpp b/src/check_type.cpp index c209a8e09..9381443fc 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2827,12 +2827,15 @@ gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finis GB_ASSERT(soa_count >= 0); field_type = alloc_type_array(old_field->type, soa_count); } else { - field_type = alloc_type_pointer(old_field->type); + field_type = alloc_type_multi_pointer(old_field->type); } Entity *new_field = alloc_entity_field(scope, old_field->token, field_type, false, old_field->Variable.field_index); t->Struct.fields[i] = new_field; add_entity(scope, new_field); new_field->flags |= EntityFlag_Used; + if (t->Struct.soa_kind != StructSoa_Fixed) { + new_field->flags |= EntityFlag_SoaPtrField; + } } else { t->Struct.fields[i] = old_field; } @@ -2948,7 +2951,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e GB_ASSERT(count >= 0); field_type = alloc_type_array(old_array->Array.elem, count); } else { - field_type = alloc_type_pointer(old_array->Array.elem); + field_type = alloc_type_multi_pointer(old_array->Array.elem); } Token token = {}; token.string = params_xyzw[i]; @@ -2957,6 +2960,9 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e soa_struct->Struct.fields[i] = new_field; add_entity(ctx, scope, nullptr, new_field); add_entity_use(ctx, nullptr, new_field); + if (soa_kind != StructSoa_Fixed) { + new_field->flags |= EntityFlag_SoaPtrField; + } } is_complete = true; @@ -2980,12 +2986,15 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e GB_ASSERT(count >= 0); field_type = alloc_type_array(old_field->type, count); } else { - field_type = alloc_type_pointer(old_field->type); + field_type = alloc_type_multi_pointer(old_field->type); } Entity *new_field = alloc_entity_field(scope, old_field->token, field_type, false, old_field->Variable.field_index); soa_struct->Struct.fields[i] = new_field; add_entity(ctx, scope, nullptr, new_field); add_entity_use(ctx, nullptr, new_field); + if (soa_kind != StructSoa_Fixed) { + new_field->flags |= EntityFlag_SoaPtrField; + } } else { soa_struct->Struct.fields[i] = old_field; } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 899b74e56..934f59d9a 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3851,27 +3851,39 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { if (ie->expr->tav.mode == Addressing_SoaVariable) { // SOA Structures for slices/dynamic arrays - GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); + GB_ASSERT_MSG(is_type_multi_pointer(type_of_expr(ie->expr)), "%s", type_to_string(type_of_expr(ie->expr))); lbValue field = lb_build_expr(p, ie->expr); lbValue index = lb_build_expr(p, ie->index); - if (!build_context.no_bounds_check) { - // TODO HACK(bill): Clean up this hack to get the length for bounds checking - // GB_ASSERT(LLVMIsALoadInst(field.value)); - - // lbValue a = {}; - // a.value = LLVMGetOperand(field.value, 0); - // a.type = alloc_type_pointer(field.type); - - // irInstr *b = &a->Instr; - // GB_ASSERT(b->kind == irInstr_StructElementPtr); - // lbValue base_struct = b->StructElementPtr.address; + Ast *se_expr = unparen_expr(ie->expr); + if (se_expr->kind == Ast_SelectorExpr) { + ast_node(se, SelectorExpr, se_expr); + lbValue len = {}; + + Type *type = base_type(type_deref(type_of_expr(se->expr))); + GB_ASSERT_MSG(is_type_soa_struct(type), "%s", type_to_string(type)); + if (type->Struct.soa_kind == StructSoa_Fixed) { + len = lb_const_int(p->module, t_int, type->Struct.soa_count); + } else { + lbAddr *found = map_get(&p->selector_addr, se_expr); + if (found) { + lbAddr addr = *found; + lbValue parent = lb_addr_get_ptr(p, addr); + if (is_type_pointer(type_deref(parent.type))) { + parent = lb_emit_load(p, parent); + } + len = lb_soa_struct_len(p, parent); + } + } - // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct)))); - // lbValue len = ir_soa_struct_len(p, base_struct); - // lb_emit_bounds_check(p, ast_token(ie->index), index, len); + if (len.value) { + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + } else { + // TODO(bill): how do you even do bounds checking here? + } } lbValue val = lb_emit_ptr_offset(p, field, index); return lb_addr(val); @@ -4218,6 +4230,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); field_src = lb_emit_array_ep(p, field_src, low); + field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type)); lb_emit_store(p, field_dst, field_src); } @@ -4233,6 +4246,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); lbValue field_src = lb_emit_struct_ev(p, base, i); field_src = lb_emit_ptr_offset(p, field_src, low); + field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type)); lb_emit_store(p, field_dst, field_src); } @@ -4247,6 +4261,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); lbValue field_src = lb_emit_struct_ev(p, base, i); field_src = lb_emit_ptr_offset(p, field_src, low); + field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type)); lb_emit_store(p, field_dst, field_src); } @@ -4989,6 +5004,11 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { sel.index[0] = addr.swizzle.indices[sel.index[0]]; } + Type *atype = type_deref(lb_addr_type(addr)); + if (is_type_soa_struct(atype)) { + map_set(&p->selector_addr, expr, addr); + } + lbValue a = lb_addr_get_ptr(p, addr); a = lb_emit_deep_field_gep(p, a, sel); return lb_addr(a); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 3c1a7ee7f..e8183027f 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1324,7 +1324,7 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { for (isize i = 0; i < field_count; i++) { Entity *field = t->Struct.fields[i]; Type *base_type = field->type; - GB_ASSERT(base_type->kind == Type_Pointer); + GB_ASSERT(base_type->kind == Type_MultiPointer); lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i); lbValue src_ptr = lb_emit_struct_ep(p, addr.addr, cast(i32)i); -- cgit v1.2.3 From a68c635c0001f4556d468ae6773bd61703c8f560 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 20 May 2024 15:00:43 +0100 Subject: Remove constant indexing for `matrix` value propagation --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c9cfb58be..32c55228b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -10157,7 +10157,7 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, o->mode = Addressing_Invalid; o->expr = node; return kind; - } else if (ok) { + } else if (ok && !is_type_matrix(t)) { ExactValue value = type_and_value_of_expr(ie->expr).value; o->mode = Addressing_Constant; bool success = false; -- cgit v1.2.3 From bc706f8b0c18f90dca0cdd664ebb82e8a4305fa3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 20 May 2024 15:04:15 +0100 Subject: Fix indexing type when using a `#row_major` matrix --- src/check_expr.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 32c55228b..013f146f6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7755,13 +7755,18 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 return true; case Type_Matrix: - *max_count = t->Matrix.column_count; if (indirection) { o->mode = Addressing_Variable; } else if (o->mode != Addressing_Variable) { o->mode = Addressing_Value; } - o->type = alloc_type_array(t->Matrix.elem, t->Matrix.row_count); + if (t->Matrix.is_row_major) { + *max_count = t->Matrix.row_count; + o->type = alloc_type_array(t->Matrix.elem, t->Matrix.column_count); + } else { + *max_count = t->Matrix.column_count; + o->type = alloc_type_array(t->Matrix.elem, t->Matrix.row_count); + } return true; case Type_Slice: -- cgit v1.2.3 From 2f35ee9671cf52b980d37fd8b1f18c8faccd951a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 22 May 2024 21:52:15 +0100 Subject: Improve errors a lot for assigning procedures of the wrong signature --- src/check_expr.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 013f146f6..a0e6b33df 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1179,15 +1179,60 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ LIT(context_name)); check_assignment_error_suggestion(c, operand, type); + Type *src = base_type(operand->type); + Type *dst = base_type(type); if (context_name == "procedure argument") { - Type *src = base_type(operand->type); - Type *dst = base_type(type); if (is_type_slice(src) && are_types_identical(src->Slice.elem, dst)) { gbString a = expr_to_string(operand->expr); error_line("\tSuggestion: Did you mean to pass the slice into the variadic parameter with ..%s?\n\n", a); gb_string_free(a); } } + if (src->kind == dst->kind && src->kind == Type_Proc) { + Type *x = src; + Type *y = dst; + bool same_inputs = are_types_identical_internal(x->Proc.params, y->Proc.params, false); + bool same_outputs = are_types_identical_internal(x->Proc.results, y->Proc.results, false); + if (same_inputs && same_outputs) { + if (x->Proc.calling_convention != y->Proc.calling_convention) { + gbString s_expected = type_to_string(y); + gbString s_got = type_to_string(x); + + error_line("\tNote: The calling conventions differ between the procedure signature types\n"); + error_line("\t Expected \"%s\", got \"%s\"\n", + proc_calling_convention_strings[y->Proc.calling_convention], + proc_calling_convention_strings[x->Proc.calling_convention]); + error_line("\t Expected: %s\n", s_expected); + error_line("\t Got: %s\n", s_got); + gb_string_free(s_got); + gb_string_free(s_expected); + } + } else if (same_inputs) { + gbString s_expected = type_to_string(y->Proc.results); + gbString s_got = type_to_string(x->Proc.results); + error_line("\tNote: The return types differ between the procedure signature types\n"); + error_line("\t Expected: %s\n", s_expected); + error_line("\t Got: %s\n", s_got); + gb_string_free(s_got); + gb_string_free(s_expected); + } else if (same_outputs) { + gbString s_expected = type_to_string(y->Proc.params); + gbString s_got = type_to_string(x->Proc.params); + error_line("\tNote: The input parameter types differ between the procedure signature types\n"); + error_line("\t Expected: %s\n", s_expected); + error_line("\t Got: %s\n", s_got); + gb_string_free(s_got); + gb_string_free(s_expected); + } else { + gbString s_expected = type_to_string(y); + gbString s_got = type_to_string(x); + error_line("\tNote: The signature type do not match whatsoever\n"); + error_line("\t Expected: %s\n", s_expected); + error_line("\t Got: %s\n", s_got); + gb_string_free(s_got); + gb_string_free(s_expected); + } + } } break; } -- cgit v1.2.3 From f3f08c264f2baa958551030a9f4af509010bf0a4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 22 May 2024 21:55:48 +0100 Subject: Be very particular with the cases for the error notes --- src/check_expr.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index a0e6b33df..5d4d6c73b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1193,21 +1193,20 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ Type *y = dst; bool same_inputs = are_types_identical_internal(x->Proc.params, y->Proc.params, false); bool same_outputs = are_types_identical_internal(x->Proc.results, y->Proc.results, false); - if (same_inputs && same_outputs) { - if (x->Proc.calling_convention != y->Proc.calling_convention) { - gbString s_expected = type_to_string(y); - gbString s_got = type_to_string(x); - - error_line("\tNote: The calling conventions differ between the procedure signature types\n"); - error_line("\t Expected \"%s\", got \"%s\"\n", - proc_calling_convention_strings[y->Proc.calling_convention], - proc_calling_convention_strings[x->Proc.calling_convention]); - error_line("\t Expected: %s\n", s_expected); - error_line("\t Got: %s\n", s_got); - gb_string_free(s_got); - gb_string_free(s_expected); - } - } else if (same_inputs) { + if (same_inputs && same_outputs && + x->Proc.calling_convention != y->Proc.calling_convention) { + gbString s_expected = type_to_string(y); + gbString s_got = type_to_string(x); + + error_line("\tNote: The calling conventions differ between the procedure signature types\n"); + error_line("\t Expected \"%s\", got \"%s\"\n", + proc_calling_convention_strings[y->Proc.calling_convention], + proc_calling_convention_strings[x->Proc.calling_convention]); + error_line("\t Expected: %s\n", s_expected); + error_line("\t Got: %s\n", s_got); + gb_string_free(s_got); + gb_string_free(s_expected); + } else if (same_inputs && !same_outputs) { gbString s_expected = type_to_string(y->Proc.results); gbString s_got = type_to_string(x->Proc.results); error_line("\tNote: The return types differ between the procedure signature types\n"); @@ -1215,7 +1214,7 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ error_line("\t Got: %s\n", s_got); gb_string_free(s_got); gb_string_free(s_expected); - } else if (same_outputs) { + } else if (!same_inputs && same_outputs) { gbString s_expected = type_to_string(y->Proc.params); gbString s_got = type_to_string(x->Proc.params); error_line("\tNote: The input parameter types differ between the procedure signature types\n"); -- cgit v1.2.3 From 64bdb3a09770b96afccd3b375b5c91214e97415b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 26 May 2024 12:17:03 +0100 Subject: Fix #3630 (first part) --- src/check_expr.cpp | 2 +- src/check_type.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5d4d6c73b..8672941c1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1805,7 +1805,7 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam case Entity_ImportName: if (!allow_import_name) { - error(n, "Use of import '%.*s' not in selector", LIT(name)); + error(n, "Use of import name '%.*s' not in the form of 'x.y'", LIT(name)); } return e; case Entity_LibraryName: diff --git a/src/check_type.cpp b/src/check_type.cpp index 9381443fc..7ed657bee 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1595,7 +1595,7 @@ gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) { return is_expr_from_a_parameter(ctx, lhs); } else if (expr->kind == Ast_Ident) { Operand x= {}; - Entity *e = check_ident(ctx, &x, expr, nullptr, nullptr, false); + Entity *e = check_ident(ctx, &x, expr, nullptr, nullptr, true); if (e->flags & EntityFlag_Param) { return true; } -- 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_expr.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 6b386631ddd7305f3111310a2ed3f921d5035298 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 4 Jun 2024 16:16:27 +0100 Subject: Improve error message suggestion for passing enums to integers --- src/check_expr.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2e008fe93..6af80eed5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -125,6 +125,8 @@ gb_internal Entity *find_polymorphic_record_entity(GenTypesData *found_gen_types gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finish); +gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y); + enum LoadDirectiveResult { LoadDirective_Success = 0, LoadDirective_Error = 1, @@ -2252,6 +2254,17 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, Type *type, i64 max_bit_size=0) { if (is_type_integer(type) && o->value.kind == ExactValue_Integer) { gbString b = type_to_string(type); + defer (gb_string_free(b)); + + if (is_type_enum(o->type)) { + if (check_is_castable_to(c, o, type)) { + gbString ot = type_to_string(o->type); + error_line("\tSuggestion: Try casting the '%s' expression to '%s'", ot, b); + gb_string_free(ot); + } + return true; + } + i64 sz = type_size_of(type); i64 bit_size = 8*sz; @@ -2301,7 +2314,6 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, } } - gb_string_free(b); return true; } -- 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_expr.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 3e159736cdf7654d5739a1340458aa23aaccbf7a Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 4 Jun 2024 19:32:23 +0200 Subject: use `#exists` to provide good errors for common missing libraries --- src/check_expr.cpp | 1 + vendor/cgltf/cgltf.odin | 22 ++++++++++++++++++---- vendor/miniaudio/common.odin | 12 ++++++++---- vendor/miniaudio/data_conversion.odin | 6 +----- vendor/miniaudio/decoding.odin | 6 +----- vendor/miniaudio/device_io_procs.odin | 6 +----- vendor/miniaudio/effects.odin | 6 +----- vendor/miniaudio/encoding.odin | 6 +----- vendor/miniaudio/engine.odin | 6 +----- vendor/miniaudio/filtering.odin | 6 +----- vendor/miniaudio/generation.odin | 6 +----- vendor/miniaudio/job_queue.odin | 6 +----- vendor/miniaudio/logging.odin | 6 +----- vendor/miniaudio/node_graph.odin | 6 +----- vendor/miniaudio/resource_manager.odin | 6 +----- vendor/miniaudio/synchronization.odin | 6 +----- vendor/miniaudio/utilities.odin | 6 +----- vendor/miniaudio/vfs.odin | 6 +----- vendor/stb/image/stb_image.odin | 25 +++++++++++++++++++------ vendor/stb/image/stb_image_resize.odin | 23 ++++++++++++++++++----- vendor/stb/image/stb_image_write.odin | 21 +++++++++++++++++---- vendor/stb/rect_pack/stb_rect_pack.odin | 21 +++++++++++++++++---- vendor/stb/truetype/stb_truetype.odin | 22 +++++++++++++++++----- vendor/stb/vorbis/stb_vorbis.odin | 24 +++++++++++++++++------- 24 files changed, 147 insertions(+), 114 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3bf2af24a..c03fcb184 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8330,6 +8330,7 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A name == "assert" || name == "defined" || name == "config" || + name == "exists" || name == "load" || name == "load_hash" || name == "load_directory" || diff --git a/vendor/cgltf/cgltf.odin b/vendor/cgltf/cgltf.odin index 024e8dfaa..a5d474a7b 100644 --- a/vendor/cgltf/cgltf.odin +++ b/vendor/cgltf/cgltf.odin @@ -1,9 +1,23 @@ package cgltf -when ODIN_OS == .Windows { foreign import lib "lib/cgltf.lib" } -else when ODIN_OS == .Linux { foreign import lib "lib/cgltf.a" } -else when ODIN_OS == .Darwin { foreign import lib "lib/darwin/cgltf.a" } -else { foreign import lib "system:cgltf" } +@(private) +LIB :: ( + "lib/cgltf.lib" when ODIN_OS == .Windows + else "lib/cgltf.a" when ODIN_OS == .Linux + else "lib/darwin/cgltf.a" when ODIN_OS == .Darwin + else "" +) + +when LIB != "" { + when !#exists(LIB) { + // Windows library is shipped with the compiler, so a Windows specific message should not be needed. + #panic("Could not find the compiled cgltf library, it can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/cgltf/src\"`") + } + + foreign import lib { LIB } +} else { + foreign import lib "system:cgltf" +} import "core:c" diff --git a/vendor/miniaudio/common.odin b/vendor/miniaudio/common.odin index b38599d96..d72c3f251 100644 --- a/vendor/miniaudio/common.odin +++ b/vendor/miniaudio/common.odin @@ -8,12 +8,16 @@ when MINIAUDIO_SHARED { #panic("Shared linking for miniaudio is not supported yet") } -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" +@(private) +LIB :: "lib/miniaudio.lib" when ODIN_OS == .Windows else "lib/miniaudio.a" + +when !#exists(LIB) { + // Windows library is shipped with the compiler, so a Windows specific message should not be needed. + #panic("Could not find the compiled miniaudio library, it can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/miniaudio/src\"`") } +foreign import lib { LIB } + BINDINGS_VERSION_MAJOR :: 0 BINDINGS_VERSION_MINOR :: 11 BINDINGS_VERSION_REVISION :: 21 diff --git a/vendor/miniaudio/data_conversion.odin b/vendor/miniaudio/data_conversion.odin index aee26bc8c..c33f54707 100644 --- a/vendor/miniaudio/data_conversion.odin +++ b/vendor/miniaudio/data_conversion.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } /************************************************************************************************************************************************************ ************************************************************************************************************************************************************* diff --git a/vendor/miniaudio/decoding.odin b/vendor/miniaudio/decoding.odin index 4433aa5a7..4860680c9 100644 --- a/vendor/miniaudio/decoding.odin +++ b/vendor/miniaudio/decoding.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } /************************************************************************************************************************************************************ diff --git a/vendor/miniaudio/device_io_procs.odin b/vendor/miniaudio/device_io_procs.odin index 0d572ae2c..21ac1afd7 100644 --- a/vendor/miniaudio/device_io_procs.odin +++ b/vendor/miniaudio/device_io_procs.odin @@ -1,10 +1,6 @@ package miniaudio -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } import "core:c" diff --git a/vendor/miniaudio/effects.odin b/vendor/miniaudio/effects.odin index 273845001..a3710ad88 100644 --- a/vendor/miniaudio/effects.odin +++ b/vendor/miniaudio/effects.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } /* Delay diff --git a/vendor/miniaudio/encoding.odin b/vendor/miniaudio/encoding.odin index 63aa45c6d..da8389b06 100644 --- a/vendor/miniaudio/encoding.odin +++ b/vendor/miniaudio/encoding.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } /************************************************************************************************************************************************************ diff --git a/vendor/miniaudio/engine.odin b/vendor/miniaudio/engine.odin index 6eabd75c2..ecd3fb39d 100644 --- a/vendor/miniaudio/engine.odin +++ b/vendor/miniaudio/engine.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } /************************************************************************************************************************************************************ diff --git a/vendor/miniaudio/filtering.odin b/vendor/miniaudio/filtering.odin index 31ddbd7a4..d1c053d20 100644 --- a/vendor/miniaudio/filtering.odin +++ b/vendor/miniaudio/filtering.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } /************************************************************************************************************************************************************** diff --git a/vendor/miniaudio/generation.odin b/vendor/miniaudio/generation.odin index 69be85234..746efcca7 100644 --- a/vendor/miniaudio/generation.odin +++ b/vendor/miniaudio/generation.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } waveform_type :: enum c.int { sine, diff --git a/vendor/miniaudio/job_queue.odin b/vendor/miniaudio/job_queue.odin index baa71c5f1..01ee31216 100644 --- a/vendor/miniaudio/job_queue.odin +++ b/vendor/miniaudio/job_queue.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } /* Slot Allocator diff --git a/vendor/miniaudio/logging.odin b/vendor/miniaudio/logging.odin index 52b1c7980..afddf8e68 100644 --- a/vendor/miniaudio/logging.odin +++ b/vendor/miniaudio/logging.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c/libc" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } MAX_LOG_CALLBACKS :: 4 diff --git a/vendor/miniaudio/node_graph.odin b/vendor/miniaudio/node_graph.odin index 09ab50a3b..63482413b 100644 --- a/vendor/miniaudio/node_graph.odin +++ b/vendor/miniaudio/node_graph.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } /************************************************************************************************************************************************************ diff --git a/vendor/miniaudio/resource_manager.odin b/vendor/miniaudio/resource_manager.odin index f27f3a53a..0284db86b 100644 --- a/vendor/miniaudio/resource_manager.odin +++ b/vendor/miniaudio/resource_manager.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } /************************************************************************************************************************************************************ diff --git a/vendor/miniaudio/synchronization.odin b/vendor/miniaudio/synchronization.odin index cd4b0a5f0..012f52c2c 100644 --- a/vendor/miniaudio/synchronization.odin +++ b/vendor/miniaudio/synchronization.odin @@ -1,10 +1,6 @@ package miniaudio -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } @(default_calling_convention="c", link_prefix="ma_") foreign lib { diff --git a/vendor/miniaudio/utilities.odin b/vendor/miniaudio/utilities.odin index d518a514a..8728f40dc 100644 --- a/vendor/miniaudio/utilities.odin +++ b/vendor/miniaudio/utilities.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } @(default_calling_convention="c", link_prefix="ma_") foreign lib { diff --git a/vendor/miniaudio/vfs.odin b/vendor/miniaudio/vfs.odin index 475d118fc..b045a1501 100644 --- a/vendor/miniaudio/vfs.odin +++ b/vendor/miniaudio/vfs.odin @@ -2,11 +2,7 @@ package miniaudio import "core:c" -when ODIN_OS == .Windows { - foreign import lib "lib/miniaudio.lib" -} else { - foreign import lib "lib/miniaudio.a" -} +foreign import lib { LIB } /************************************************************************************************************************************************************ diff --git a/vendor/stb/image/stb_image.odin b/vendor/stb/image/stb_image.odin index c7caf801e..828a1c2bd 100644 --- a/vendor/stb/image/stb_image.odin +++ b/vendor/stb/image/stb_image.odin @@ -2,13 +2,26 @@ package stb_image import c "core:c/libc" -#assert(size_of(c.int) == size_of(b32)) - - when ODIN_OS == .Windows { foreign import stbi "../lib/stb_image.lib" } -else when ODIN_OS == .Linux { foreign import stbi "../lib/stb_image.a" } -else when ODIN_OS == .Darwin { foreign import stbi "../lib/darwin/stb_image.a" } -else { foreign import stbi "system:stb_image" } +@(private) +LIB :: ( + "../lib/stb_image.lib" when ODIN_OS == .Windows + else "../lib/stb_image.a" when ODIN_OS == .Linux + else "../lib/darwin/stb_image.a" when ODIN_OS == .Darwin + else "" +) + +when LIB != "" { + when !#exists(LIB) { + // The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed. + #panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`") + } + + foreign import stbi { LIB } +} else { + foreign import stbi "system:stb_image" +} +#assert(size_of(c.int) == size_of(b32)) #assert(size_of(b32) == size_of(c.int)) // diff --git a/vendor/stb/image/stb_image_resize.odin b/vendor/stb/image/stb_image_resize.odin index c464964df..d407a1852 100644 --- a/vendor/stb/image/stb_image_resize.odin +++ b/vendor/stb/image/stb_image_resize.odin @@ -2,11 +2,24 @@ package stb_image import c "core:c/libc" - when ODIN_OS == .Windows { foreign import lib "../lib/stb_image_resize.lib" } -else when ODIN_OS == .Linux { foreign import lib "../lib/stb_image_resize.a" } -else when ODIN_OS == .Darwin { foreign import lib "../lib/darwin/stb_image_resize.a" } -else { foreign import lib "system:stb_image_resize" } - +@(private) +RESIZE_LIB :: ( + "../lib/stb_image_resize.lib" when ODIN_OS == .Windows + else "../lib/stb_image_resize.a" when ODIN_OS == .Linux + else "../lib/darwin/stb_image_resize.a" when ODIN_OS == .Darwin + else "" +) + +when RESIZE_LIB != "" { + when !#exists(RESIZE_LIB) { + // The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed. + #panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`") + } + + foreign import lib { RESIZE_LIB } +} else { + foreign import lib "system:stb_image_resize" +} ////////////////////////////////////////////////////////////////////////////// // diff --git a/vendor/stb/image/stb_image_write.odin b/vendor/stb/image/stb_image_write.odin index 9ed97eb48..f030f1e28 100644 --- a/vendor/stb/image/stb_image_write.odin +++ b/vendor/stb/image/stb_image_write.odin @@ -2,11 +2,24 @@ package stb_image import c "core:c/libc" - when ODIN_OS == .Windows { foreign import stbiw "../lib/stb_image_write.lib" } -else when ODIN_OS == .Linux { foreign import stbiw "../lib/stb_image_write.a" } -else when ODIN_OS == .Darwin { foreign import stbiw "../lib/darwin/stb_image_write.a" } -else { foreign import stbiw "system:stb_image_write" } +@(private) +WRITE_LIB :: ( + "../lib/stb_image_write.lib" when ODIN_OS == .Windows + else "../lib/stb_image_write.a" when ODIN_OS == .Linux + else "../lib/darwin/stb_image_write.a" when ODIN_OS == .Darwin + else "" +) +when WRITE_LIB != "" { + when !#exists(WRITE_LIB) { + // The STB libraries are shipped with the compiler on Windows so a Windows specific message should not be needed. + #panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`") + } + + foreign import stbiw { WRITE_LIB } +} else { + foreign import stbiw "system:stb_image_write" +} write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int) diff --git a/vendor/stb/rect_pack/stb_rect_pack.odin b/vendor/stb/rect_pack/stb_rect_pack.odin index 3a2544b81..6c0b56378 100644 --- a/vendor/stb/rect_pack/stb_rect_pack.odin +++ b/vendor/stb/rect_pack/stb_rect_pack.odin @@ -4,10 +4,23 @@ import "core:c" #assert(size_of(b32) == size_of(c.int)) - when ODIN_OS == .Windows { foreign import lib "../lib/stb_rect_pack.lib" } -else when ODIN_OS == .Linux { foreign import lib "../lib/stb_rect_pack.a" } -else when ODIN_OS == .Darwin { foreign import lib "../lib/darwin/stb_rect_pack.a" } -else { foreign import lib "system:stb_rect_pack" } +@(private) +LIB :: ( + "../lib/stb_rect_pack.lib" when ODIN_OS == .Windows + else "../lib/stb_rect_pack.a" when ODIN_OS == .Linux + else "../lib/darwin/stb_rect_pack.a" when ODIN_OS == .Darwin + else "" +) + +when LIB != "" { + when !#exists(LIB) { + #panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`") + } + + foreign import lib { LIB } +} else { + foreign import lib "system:stb_rect_pack" +} Coord :: distinct c.int _MAXVAL :: max(Coord) diff --git a/vendor/stb/truetype/stb_truetype.odin b/vendor/stb/truetype/stb_truetype.odin index 1600041de..876138c3a 100644 --- a/vendor/stb/truetype/stb_truetype.odin +++ b/vendor/stb/truetype/stb_truetype.odin @@ -3,11 +3,23 @@ package stb_truetype import c "core:c" import stbrp "vendor:stb/rect_pack" - when ODIN_OS == .Windows { foreign import stbtt "../lib/stb_truetype.lib" } -else when ODIN_OS == .Linux { foreign import stbtt "../lib/stb_truetype.a" } -else when ODIN_OS == .Darwin { foreign import stbtt "../lib/darwin/stb_truetype.a" } -else { foreign import stbtt "system:stb_truetype" } - +@(private) +LIB :: ( + "../lib/stb_truetype.lib" when ODIN_OS == .Windows + else "../lib/stb_truetype.a" when ODIN_OS == .Linux + else "../lib/darwin/stb_truetype.a" when ODIN_OS == .Darwin + else "" +) + +when LIB != "" { + when !#exists(LIB) { + #panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`") + } + + foreign import stbtt { LIB } +} else { + foreign import stbtt "system:stb_truetype" +} /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// diff --git a/vendor/stb/vorbis/stb_vorbis.odin b/vendor/stb/vorbis/stb_vorbis.odin index 0c887a473..867ffb86d 100644 --- a/vendor/stb/vorbis/stb_vorbis.odin +++ b/vendor/stb/vorbis/stb_vorbis.odin @@ -2,13 +2,23 @@ package stb_vorbis import c "core:c/libc" - - when ODIN_OS == .Windows { foreign import lib "../lib/stb_vorbis.lib" } -else when ODIN_OS == .Linux { foreign import lib "../lib/stb_vorbis.a" } -else when ODIN_OS == .Darwin { foreign import lib "../lib/darwin/stb_vorbis.a" } -else { foreign import lib "system:stb_vorbis" } - - +@(private) +LIB :: ( + "../lib/stb_vorbis.lib" when ODIN_OS == .Windows + else "../lib/stb_vorbis.a" when ODIN_OS == .Linux + else "../lib/darwin/stb_vorbis.a" when ODIN_OS == .Darwin + else "" +) + +when LIB != "" { + when !#exists(LIB) { + #panic("Could not find the compiled STB libraries, they can be compiled by running `make -C \"" + ODIN_ROOT + "vendor/stb/src\"`") + } + + foreign import lib { LIB } +} else { + foreign import lib "system:stb_vorbis" +} /////////// THREAD SAFETY -- cgit v1.2.3 From cbabcb0907e6430571c14d21fcb09c150275d99b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 5 Jun 2024 15:43:15 +0100 Subject: Fix #3682 --- src/check_expr.cpp | 7 +++++++ src/llvm_backend_expr.cpp | 20 ++++++++++++++++++-- src/types.cpp | 9 +++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 0830f65bd..d2d01deda 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8866,6 +8866,10 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, SliceArray.elem; break; + case Type_BitField: + is_constant = false; + ft = bt->BitField.fields[index]->type; + break; default: GB_PANIC("invalid type: %s", type_to_string(ft)); break; @@ -8892,6 +8896,9 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, SliceArray.elem; break; + case Type_BitField: + nested_ft = bt->BitField.fields[index]->type; + break; default: GB_PANIC("invalid type %s", type_to_string(nested_ft)); break; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index c12489598..7772ba930 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4533,10 +4533,26 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (lb_is_nested_possibly_constant(type, sel, elem)) { continue; } - lbValue dst = lb_emit_deep_field_gep(p, comp_lit_ptr, sel); field_expr = lb_build_expr(p, elem); field_expr = lb_emit_conv(p, field_expr, sel.entity->type); - lb_emit_store(p, dst, field_expr); + if (sel.is_bit_field) { + Selection sub_sel = trim_selection(sel); + lbValue trimmed_dst = lb_emit_deep_field_gep(p, comp_lit_ptr, sub_sel); + Type *bf = base_type(type_deref(trimmed_dst.type)); + if (is_type_pointer(bf)) { + trimmed_dst = lb_emit_load(p, trimmed_dst); + bf = base_type(type_deref(trimmed_dst.type)); + } + GB_ASSERT(bf->kind == Type_BitField); + + isize idx = sel.index[sel.index.count-1]; + lbAddr dst = lb_addr_bit_field(trimmed_dst, bf->BitField.fields[idx]->type, bf->BitField.bit_offsets[idx], bf->BitField.bit_sizes[idx]); + lb_addr_store(p, dst, field_expr); + + } else { + lbValue dst = lb_emit_deep_field_gep(p, comp_lit_ptr, sel); + lb_emit_store(p, dst, field_expr); + } continue; } diff --git a/src/types.cpp b/src/types.cpp index e568d2af2..618e5bd8a 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -457,6 +457,15 @@ gb_internal Selection sub_selection(Selection const &sel, isize offset) { return res; } +gb_internal Selection trim_selection(Selection const &sel) { + Selection res = {}; + res.index.data = sel.index.data; + res.index.count = gb_max(sel.index.count - 1, 0); + res.index.capacity = res.index.count; + return res; +} + + gb_global Type basic_types[] = { {Type_Basic, {Basic_Invalid, 0, 0, STR_LIT("invalid type")}}, -- 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_expr.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 4b52f7fe2bd68d74efffa55ef8b4582164c1e268 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 9 Jun 2024 13:35:22 +0100 Subject: Fix #3713 --- src/check_expr.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ad546858c..4115cd1e9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3336,11 +3336,12 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { } if (is_type_untyped(x->type)) { - Type *final_type = type; - if (is_const_expr && !is_type_constant_type(type)) { - final_type = default_type(x->type); - } - update_untyped_expr_type(c, x->expr, final_type, true); + convert_to_typed(c, x, type); + // Type *final_type = type; + // if (is_const_expr && !is_type_constant_type(type)) { + // final_type = default_type(x->type); + // } + // update_untyped_expr_type(c, x->expr, final_type, true); } else { Type *src = core_type(x->type); Type *dst = core_type(type); @@ -4286,7 +4287,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar } else { switch (operand->type->Basic.kind) { case Basic_UntypedBool: - if (!is_type_boolean(target_type)) { + if (!is_type_boolean(target_type) && + !is_type_integer(target_type)) { operand->mode = Addressing_Invalid; convert_untyped_error(c, operand, target_type); return; @@ -7527,9 +7529,6 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } operand->type = t; operand->expr = call; - if (operand->mode != Addressing_Invalid) { - update_untyped_expr_type(c, arg, t, false); - } break; } } -- cgit v1.2.3 From c17981ac38ace6cac12463029273d16068bf23c3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 9 Jun 2024 14:02:01 +0100 Subject: Add edge case to `error_operand_no_value` --- src/check_expr.cpp | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4115cd1e9..1e6d6e2ab 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -281,8 +281,20 @@ gb_internal void error_operand_not_expression(Operand *o) { gb_internal void error_operand_no_value(Operand *o) { if (o->mode == Addressing_NoValue) { - gbString err = expr_to_string(o->expr); Ast *x = unparen_expr(o->expr); + + if (x->kind == Ast_CallExpr) { + Ast *p = unparen_expr(x->CallExpr.proc); + if (p->kind == Ast_BasicDirective) { + String tag = p->BasicDirective.name.string; + if (tag == "panic" || + tag == "assert") { + return; + } + } + } + + gbString err = expr_to_string(o->expr); if (x->kind == Ast_CallExpr) { error(o->expr, "'%s' call does not return a value and cannot be used as a value", err); } else { @@ -3336,12 +3348,11 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { } if (is_type_untyped(x->type)) { - convert_to_typed(c, x, type); - // Type *final_type = type; - // if (is_const_expr && !is_type_constant_type(type)) { - // final_type = default_type(x->type); - // } - // update_untyped_expr_type(c, x->expr, final_type, true); + Type *final_type = type; + if (is_const_expr && !is_type_constant_type(type)) { + final_type = default_type(x->type); + } + update_untyped_expr_type(c, x->expr, final_type, true); } else { Type *src = core_type(x->type); Type *dst = core_type(type); @@ -4287,8 +4298,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar } else { switch (operand->type->Basic.kind) { case Basic_UntypedBool: - if (!is_type_boolean(target_type) && - !is_type_integer(target_type)) { + if (!is_type_boolean(target_type)) { operand->mode = Addressing_Invalid; convert_untyped_error(c, operand, target_type); return; @@ -7529,6 +7539,9 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } operand->type = t; operand->expr = call; + if (operand->mode != Addressing_Invalid) { + update_untyped_expr_type(c, arg, t, false); + } break; } } @@ -8336,7 +8349,7 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A name == "assert" || name == "defined" || name == "config" || - name == "exists" || + name == "exists" || name == "load" || name == "load_hash" || name == "load_directory" || -- cgit v1.2.3 From ef7c6b98951aacc72bd25750e1c4a3a8c30c7d06 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 9 Jun 2024 14:07:07 +0100 Subject: Re Fix #3713 --- src/check_expr.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 1e6d6e2ab..13d0e277d 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3350,6 +3350,9 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { if (is_type_untyped(x->type)) { Type *final_type = type; if (is_const_expr && !is_type_constant_type(type)) { + if (is_type_union(type)) { + convert_to_typed(c, x, type); + } final_type = default_type(x->type); } update_untyped_expr_type(c, x->expr, final_type, true); @@ -4298,7 +4301,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar } else { switch (operand->type->Basic.kind) { case Basic_UntypedBool: - if (!is_type_boolean(target_type)) { + if (!is_type_boolean(target_type) && + !is_type_integer(target_type)) { operand->mode = Addressing_Invalid; convert_untyped_error(c, operand, target_type); return; -- cgit v1.2.3 From 45d1328a85818fc77f2aacc77fa6ce0cfbce3473 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 10 Jun 2024 00:50:16 -0400 Subject: Fix typo in a `#force_inline` error message --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 13d0e277d..641f70566 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7672,7 +7672,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c if (decl->proc_lit) { ast_node(pl, ProcLit, decl->proc_lit); if (pl->inlining == ProcInlining_no_inline) { - error(call, "'#force_inline' cannot be applied to a procedure that has be marked as '#force_no_inline'"); + error(call, "'#force_inline' cannot be applied to a procedure that has been marked as '#force_no_inline'"); } } } -- 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_expr.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 f57c03c1707f48608bcb3bc87aeee91af60e6d63 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jun 2024 12:40:29 +0100 Subject: Improve matrix type hinting rules a little --- src/check_expr.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 01cba881e..742909701 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3568,6 +3568,8 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand // prefer the named type x->type = y->type; } + // finish + return; } else { bool is_row_major = xt->Matrix.is_row_major && yt->Matrix.is_row_major; x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count, nullptr, nullptr, is_row_major); -- cgit v1.2.3 From c5f7788652c6f46ae9b1588c8e3638d58c49c92b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 12 Jun 2024 12:54:57 +0100 Subject: Check to see if matrices are exactly the same type --- src/check_expr.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 742909701..0f9bb781e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3564,12 +3564,13 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand x->mode = Addressing_Value; if (are_types_identical(xt, yt)) { + if (are_types_identical(x->type, y->type)) { + return; + } if (!is_type_named(x->type) && is_type_named(y->type)) { // prefer the named type x->type = y->type; } - // finish - return; } else { bool is_row_major = xt->Matrix.is_row_major && yt->Matrix.is_row_major; x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count, nullptr, nullptr, is_row_major); -- cgit v1.2.3 From 33270f14a41a61137351907ccaa5317afbe47ad5 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 12 Jun 2024 15:31:43 -0400 Subject: Fix #3739 --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 0f9bb781e..359b30276 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2550,7 +2550,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * error_line("\tSuggestion: Did you want to pass the iterable value to the for statement by pointer to get addressable semantics?\n"); } - if (is_type_map(parent_type)) { + if (parent_type != nullptr && is_type_map(parent_type)) { error_line("\t Prefer doing 'for key, &%.*s in ...'\n", LIT(e->token.string)); } else { error_line("\t Prefer doing 'for &%.*s in ...'\n", LIT(e->token.string)); -- cgit v1.2.3 From 78a5a27212a6b892e32e58a84ea0c25cd83fac3c Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 16 Jun 2024 12:27:42 -0400 Subject: Fix `bit_set` construction crash on constant non-integer field --- src/check_expr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 359b30276..e548eac88 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9819,7 +9819,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (tav.mode != Addressing_Constant) { continue; } - GB_ASSERT(tav.value.kind == ExactValue_Integer); + if (tav.value.kind != ExactValue_Integer) { + continue; + } i64 v = big_int_to_i64(&tav.value.value_integer); i64 lower = bt->BitSet.lower; u64 index = cast(u64)(v-lower); -- cgit v1.2.3 From 56383e45a7441fc789cd44c5e0dbaf9b2079a0f1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Jun 2024 11:44:00 +0100 Subject: Fix #3768 --- src/check_expr.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e548eac88..a605957bb 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2606,6 +2606,11 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * if (o->mode == Addressing_Constant) { Type *type = base_type(o->type); if (!is_type_constant_type(o->type)) { + if (is_type_array_like(o->type)) { + o->mode = Addressing_Value; + return; + } + gbString xt = type_to_string(o->type); gbString err_str = expr_to_string(node); error(op, "Invalid type, '%s', for constant unary expression '%s'", xt, err_str); -- cgit v1.2.3 From c9884906d9aa06de407bd32c188230f07201d638 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Jun 2024 12:15:55 +0100 Subject: Add `#directory` --- src/check_expr.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index a605957bb..cddcc05f2 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8327,6 +8327,14 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A } o->type = t_untyped_string; o->value = exact_value_string(file); + } else if (name == "directory") { + String file = get_file_path_string(bd->token.pos.file_id); + String path = dir_from_path(file); + if (build_context.obfuscate_source_code_locations) { + path = obfuscate_string(path, "D"); + } + o->type = t_untyped_string; + o->value = exact_value_string(path); } else if (name == "line") { i32 line = bd->token.pos.line; if (build_context.obfuscate_source_code_locations) { -- cgit v1.2.3 From f58eded5d260917a1e86140b10be94f6f2266a21 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 22 Jun 2024 11:45:43 -0400 Subject: Fix print segfault by missing argument in `or_*` shadowed error --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cddcc05f2..27e750668 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8727,7 +8727,7 @@ gb_internal ExprKind check_or_branch_expr(CheckerContext *c, Operand *o, Ast *no // okay } else { gbString s = type_to_string(right_type); - error(node, "'%.*s' requires a boolean or nil-able type, got %s", s); + error(node, "'%.*s' requires a boolean or nil-able type, got %s", LIT(name), s); gb_string_free(s); } } -- cgit v1.2.3 From 5a9698e8cb8701b122cb484d5fef7e878dae6974 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 28 Jun 2024 09:08:57 +0100 Subject: Properly fix #3820 --- src/check_expr.cpp | 9 ++++++-- src/llvm_backend_expr.cpp | 57 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 15 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 27e750668..891378b99 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4431,9 +4431,14 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar defer (gb_string_free(type_str)); if (valid_count == 1) { + Type *new_type = t->Union.variants[first_success_index]; + target_type = new_type; + if (is_type_union(new_type)) { + convert_to_typed(c, operand, new_type); + break; + } + operand->type = new_type; operand->mode = Addressing_Value; - operand->type = t->Union.variants[first_success_index]; - target_type = t->Union.variants[first_success_index]; break; } else if (valid_count > 1) { ERROR_BLOCK(); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 52dad6547..46b8fa3cb 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2044,22 +2044,59 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } if (is_type_union(dst)) { - for (Type *vt : dst->Union.variants) { - if (are_types_identical(vt, src_type)) { + if (dst->Union.variants.count == 1) { + Type *vt = dst->Union.variants[0]; + if (internal_check_is_assignable_to(src_type, vt)) { + value = lb_emit_conv(p, value, vt); lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); return lb_addr_load(p, parent); } } - if (dst->Union.variants.count == 1) { - Type *vt = dst->Union.variants[0]; - if (internal_check_is_assignable_to(src_type, vt)) { - value = lb_emit_conv(p, value, vt); + for (Type *vt : dst->Union.variants) { + if (are_types_identical(src_type, vt)) { lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); return lb_addr_load(p, parent); } } + ValidIndexAndScore *valids = gb_alloc_array(temporary_allocator(), ValidIndexAndScore, dst->Union.variants.count); + isize valid_count = 0; + isize first_success_index = -1; + for_array(i, dst->Union.variants) { + Type *vt = dst->Union.variants[i]; + i64 score = 0; + if (internal_check_is_assignable_to(src_type, vt)) { + valids[valid_count].index = i; + valids[valid_count].score = score; + valid_count += 1; + if (first_success_index < 0) { + first_success_index = i; + } + } + } + if (valid_count > 1) { + gb_sort_array(valids, valid_count, valid_index_and_score_cmp); + i64 best_score = valids[0].score; + for (isize i = 1; i < valid_count; i++) { + auto v = valids[i]; + if (best_score > v.score) { + valid_count = i; + break; + } + best_score = v.score; + } + first_success_index = valids[0].index; + } + + if (valid_count == 1) { + Type *vt = dst->Union.variants[first_success_index]; + value = lb_emit_conv(p, value, vt); + lbAddr parent = lb_add_local_generated(p, t, true); + lb_emit_store_union_variant(p, parent.addr, value, vt); + return lb_addr_load(p, parent); + } + } // NOTE(bill): This has to be done before 'Pointer <-> Pointer' as it's @@ -3284,13 +3321,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %s\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), token_pos_to_string(expr_pos), LIT(p->name), type_to_string(p->type)); - if (tv.value.kind != ExactValue_Invalid && !is_type_union(type)) { - // NOTE(bill): The commented out code below is just for debug purposes only - // if (is_type_untyped(type)) { - // gb_printf_err("%s %s : %s @ %p\n", token_pos_to_string(expr_pos), expr_to_string(expr), type_to_string(expr->tav.type), expr); - // GB_PANIC("%s\n", type_to_string(tv.type)); - // } - + if (tv.value.kind != ExactValue_Invalid) { // NOTE(bill): Short on constant values return lb_const_value(p->module, type, tv.value); } else if (tv.mode == Addressing_Type) { -- cgit v1.2.3 From 6496432b8056eeecd9ba396148f7c458a5cc02ac Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Fri, 28 Jun 2024 22:49:24 -0400 Subject: Add `-vet-identical-cast` --- src/build_settings.cpp | 5 ++++- src/check_expr.cpp | 23 +++++++++++++++++++++-- src/main.cpp | 7 +++++++ 3 files changed, 32 insertions(+), 3 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 4b348256b..f44179da0 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -742,10 +742,11 @@ enum VetFlags : u64 { VetFlag_UnusedVariables = 1u<<5, VetFlag_UnusedImports = 1u<<6, VetFlag_Deprecated = 1u<<7, + VetFlag_IdenticalCast = 1u<<8, VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports, - VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt|VetFlag_Deprecated, + VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt|VetFlag_Deprecated|VetFlag_IdenticalCast, VetFlag_Using = VetFlag_UsingStmt|VetFlag_UsingParam, }; @@ -769,6 +770,8 @@ u64 get_vet_flag_from_name(String const &name) { return VetFlag_Semicolon; } else if (name == "deprecated") { return VetFlag_Deprecated; + } else if (name == "identical-cast") { + return VetFlag_IdenticalCast; } return VetFlag_NONE; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 891378b99..7d2f10c95 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3310,7 +3310,7 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) } -gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { +gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forbid_identical = false) { if (!is_operand_value(*x)) { error(x->expr, "Only values can be casted"); x->mode = Addressing_Invalid; @@ -3382,6 +3382,25 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { add_package_dependency(c, "runtime", "gnu_f2h_ieee", REQUIRE); } } + if (forbid_identical && check_vet_flags(c) & VetFlag_IdenticalCast) { + Type *src_exact = x->type; + Type *dst_exact = type; + + if (src_exact != nullptr && + dst_exact != nullptr && + // If we check polymorphic procedures, we risk erring on + // identical casts that cannot be foreseen or otherwise + // forbidden, so just skip them. + (c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig)) && + src_exact == dst_exact) + { + gbString oper_str = expr_to_string(x->expr); + gbString to_type = type_to_string(dst_exact); + error(x->expr, "Unneeded cast of `%s` to identical type `%s`", oper_str, to_type); + gb_string_free(oper_str); + gb_string_free(to_type); + } + } } x->type = type; @@ -10718,7 +10737,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast check_transmute(c, node, o, type); break; case Token_cast: - check_cast(c, o, type); + check_cast(c, o, type, true); break; default: error(node, "Invalid AST: Invalid casting expression"); diff --git a/src/main.cpp b/src/main.cpp index b24796559..aa701b61b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -300,6 +300,7 @@ enum BuildFlagKind { BuildFlag_VetUsingParam, BuildFlag_VetStyle, BuildFlag_VetSemicolon, + BuildFlag_VetIdenticalCast, BuildFlag_CustomAttribute, BuildFlag_IgnoreUnknownAttributes, @@ -499,6 +500,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_VetUsingParam, str_lit("vet-using-param"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetStyle, str_lit("vet-style"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetSemicolon, str_lit("vet-semicolon"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetIdenticalCast, str_lit("vet-identical-cast"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_CustomAttribute, str_lit("custom-attribute"), BuildFlagParam_String, Command__does_check, true); add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); @@ -1152,6 +1154,7 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break; case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break; case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break; + case BuildFlag_VetIdenticalCast: build_context.vet_flags |= VetFlag_IdenticalCast; break; case BuildFlag_CustomAttribute: { @@ -2243,6 +2246,10 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-vet-semicolon"); print_usage_line(2, "Errs on unneeded semicolons."); print_usage_line(0, ""); + + print_usage_line(1, "-vet-identical-cast"); + print_usage_line(2, "Errs on casting a value to its own type."); + print_usage_line(0, ""); } if (check) { -- cgit v1.2.3 From 704530497b166dfa6fcee8f2c95a9e492a78a024 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 29 Jun 2024 11:44:45 +0100 Subject: Rename `-vet-identical-cast` to `-vet-cast`; with minor code clean up --- src/build_settings.cpp | 8 ++++---- src/check_expr.cpp | 16 ++++++++-------- src/main.cpp | 10 +++++----- 3 files changed, 17 insertions(+), 17 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index f44179da0..f9c426487 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -742,11 +742,11 @@ enum VetFlags : u64 { VetFlag_UnusedVariables = 1u<<5, VetFlag_UnusedImports = 1u<<6, VetFlag_Deprecated = 1u<<7, - VetFlag_IdenticalCast = 1u<<8, + VetFlag_Cast = 1u<<8, VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports, - VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt|VetFlag_Deprecated|VetFlag_IdenticalCast, + VetFlag_All = VetFlag_Unused|VetFlag_Shadowing|VetFlag_UsingStmt|VetFlag_Deprecated|VetFlag_Cast, VetFlag_Using = VetFlag_UsingStmt|VetFlag_UsingParam, }; @@ -770,8 +770,8 @@ u64 get_vet_flag_from_name(String const &name) { return VetFlag_Semicolon; } else if (name == "deprecated") { return VetFlag_Deprecated; - } else if (name == "identical-cast") { - return VetFlag_IdenticalCast; + } else if (name == "cast") { + return VetFlag_Cast; } return VetFlag_NONE; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7d2f10c95..2fa491417 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3382,18 +3382,18 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forb add_package_dependency(c, "runtime", "gnu_f2h_ieee", REQUIRE); } } - if (forbid_identical && check_vet_flags(c) & VetFlag_IdenticalCast) { + // If we check polymorphic procedures, we risk erring on + // identical casts that cannot be foreseen or otherwise + // forbidden, so just skip them. + if (forbid_identical && check_vet_flags(c) & VetFlag_Cast && + (c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig))) { Type *src_exact = x->type; Type *dst_exact = type; if (src_exact != nullptr && - dst_exact != nullptr && - // If we check polymorphic procedures, we risk erring on - // identical casts that cannot be foreseen or otherwise - // forbidden, so just skip them. - (c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig)) && - src_exact == dst_exact) - { + dst_exact != nullptr && + are_types_identical(src_exact, dst_exact) + ) { gbString oper_str = expr_to_string(x->expr); gbString to_type = type_to_string(dst_exact); error(x->expr, "Unneeded cast of `%s` to identical type `%s`", oper_str, to_type); diff --git a/src/main.cpp b/src/main.cpp index aa701b61b..62aeccaf5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -300,7 +300,7 @@ enum BuildFlagKind { BuildFlag_VetUsingParam, BuildFlag_VetStyle, BuildFlag_VetSemicolon, - BuildFlag_VetIdenticalCast, + BuildFlag_VetCast, BuildFlag_CustomAttribute, BuildFlag_IgnoreUnknownAttributes, @@ -500,7 +500,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_VetUsingParam, str_lit("vet-using-param"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetStyle, str_lit("vet-style"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetSemicolon, str_lit("vet-semicolon"), BuildFlagParam_None, Command__does_check); - add_flag(&build_flags, BuildFlag_VetIdenticalCast, str_lit("vet-identical-cast"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetCast, str_lit("vet-cast"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_CustomAttribute, str_lit("custom-attribute"), BuildFlagParam_String, Command__does_check, true); add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); @@ -1154,7 +1154,7 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break; case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break; case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break; - case BuildFlag_VetIdenticalCast: build_context.vet_flags |= VetFlag_IdenticalCast; break; + case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break; case BuildFlag_CustomAttribute: { @@ -2247,8 +2247,8 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Errs on unneeded semicolons."); print_usage_line(0, ""); - print_usage_line(1, "-vet-identical-cast"); - print_usage_line(2, "Errs on casting a value to its own type."); + print_usage_line(1, "-vet-cast"); + print_usage_line(2, "Errs on casting a value to its own type or using `transmute` rather than `cast`."); print_usage_line(0, ""); } -- cgit v1.2.3 From 4b71c47fd5e70f0f96e139e17637cf5de1beb2fc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 29 Jun 2024 12:02:31 +0100 Subject: Check for unneeded `transmute` with `-vet-cast` --- base/runtime/random_generator.odin | 2 +- core/compress/shoco/shoco.odin | 9 ++--- core/crypto/_edwards25519/edwards25519.odin | 4 +-- core/crypto/_edwards25519/edwards25519_scalar.odin | 4 +-- core/crypto/_fiat/field_curve25519/field.odin | 4 +-- core/crypto/_fiat/field_poly1305/field.odin | 4 +-- core/crypto/kmac/kmac.odin | 10 +++--- core/crypto/legacy/keccak/keccak.odin | 10 +++--- core/crypto/ristretto255/ristretto255.odin | 6 ++-- core/crypto/ristretto255/ristretto255_scalar.odin | 2 +- core/crypto/sha3/sha3.odin | 10 +++--- core/crypto/shake/shake.odin | 16 ++++----- core/crypto/tuplehash/tuplehash.odin | 14 ++++---- core/image/qoi/qoi.odin | 6 ++-- core/os/os_darwin.odin | 4 +-- core/os/os_freebsd.odin | 4 +-- core/os/os_linux.odin | 3 +- core/sys/info/cpu_intel.odin | 2 +- core/sys/linux/wrappers.odin | 4 +-- src/check_expr.cpp | 38 +++++++++++++++------- 20 files changed, 82 insertions(+), 74 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/base/runtime/random_generator.odin b/base/runtime/random_generator.odin index 95ba6ece9..94201efac 100644 --- a/base/runtime/random_generator.odin +++ b/base/runtime/random_generator.odin @@ -89,7 +89,7 @@ default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode, switch len(p) { case size_of(u64): // Fast path for a 64-bit destination. - intrinsics.unaligned_store(transmute(^u64)raw_data(p), read_u64(r)) + intrinsics.unaligned_store((^u64)(raw_data(p)), read_u64(r)) case: // All other cases. pos := i8(0) diff --git a/core/compress/shoco/shoco.odin b/core/compress/shoco/shoco.odin index 3c1f412ba..c0259ff75 100644 --- a/core/compress/shoco/shoco.odin +++ b/core/compress/shoco/shoco.odin @@ -274,12 +274,9 @@ compress_string_to_buffer :: proc(input: string, output: []u8, model := DEFAULT_ out_ptr := raw_data(output[out:]) switch pack.bytes_packed { - case 4: - intrinsics.unaligned_store(transmute(^u32)out_ptr, code) - case 2: - intrinsics.unaligned_store(transmute(^u16)out_ptr, u16(code)) - case 1: - intrinsics.unaligned_store(transmute(^u8)out_ptr, u8(code)) + case 4: intrinsics.unaligned_store((^u32)(out_ptr), code) + case 2: intrinsics.unaligned_store((^u16)(out_ptr), u16(code)) + case 1: intrinsics.unaligned_store( (^u8)(out_ptr), u8(code)) case: return out, .Unknown_Compression_Method } diff --git a/core/crypto/_edwards25519/edwards25519.odin b/core/crypto/_edwards25519/edwards25519.odin index 952bb9ef8..6495f7a3a 100644 --- a/core/crypto/_edwards25519/edwards25519.odin +++ b/core/crypto/_edwards25519/edwards25519.odin @@ -110,7 +110,7 @@ ge_set_bytes :: proc "contextless" (ge: ^Group_Element, b: []byte) -> bool { if len(b) != 32 { intrinsics.trap() } - b_ := transmute(^[32]byte)(raw_data(b)) + b_ := (^[32]byte)(raw_data(b)) // Do the work in a scratch element, so that ge is unchanged on // failure. @@ -169,7 +169,7 @@ ge_bytes :: proc "contextless" (ge: ^Group_Element, dst: []byte) { if len(dst) != 32 { intrinsics.trap() } - dst_ := transmute(^[32]byte)(raw_data(dst)) + dst_ := (^[32]byte)(raw_data(dst)) // Convert the element to affine (x, y) representation. x, y, z_inv: field.Tight_Field_Element = ---, ---, --- diff --git a/core/crypto/_edwards25519/edwards25519_scalar.odin b/core/crypto/_edwards25519/edwards25519_scalar.odin index 2644fe5f7..e21fa3755 100644 --- a/core/crypto/_edwards25519/edwards25519_scalar.odin +++ b/core/crypto/_edwards25519/edwards25519_scalar.odin @@ -28,7 +28,7 @@ sc_set_bytes :: proc "contextless" (sc: ^Scalar, b: []byte) -> bool { if len(b) != 32 { intrinsics.trap() } - b_ := transmute(^[32]byte)(raw_data(b)) + b_ := (^[32]byte)(raw_data(b)) return field.fe_from_bytes(sc, b_) } @@ -36,7 +36,7 @@ sc_set_bytes_rfc8032 :: proc "contextless" (sc: ^Scalar, b: []byte) { if len(b) != 32 { intrinsics.trap() } - b_ := transmute(^[32]byte)(raw_data(b)) + b_ := (^[32]byte)(raw_data(b)) field.fe_from_bytes_rfc8032(sc, b_) } diff --git a/core/crypto/_fiat/field_curve25519/field.odin b/core/crypto/_fiat/field_curve25519/field.odin index 8a8202ac4..04fc87659 100644 --- a/core/crypto/_fiat/field_curve25519/field.odin +++ b/core/crypto/_fiat/field_curve25519/field.odin @@ -6,13 +6,13 @@ import "core:mem" fe_relax_cast :: #force_inline proc "contextless" ( arg1: ^Tight_Field_Element, ) -> ^Loose_Field_Element { - return transmute(^Loose_Field_Element)(arg1) + return (^Loose_Field_Element)(arg1) } fe_tighten_cast :: #force_inline proc "contextless" ( arg1: ^Loose_Field_Element, ) -> ^Tight_Field_Element { - return transmute(^Tight_Field_Element)(arg1) + return (^Tight_Field_Element)(arg1) } fe_clear :: proc "contextless" ( diff --git a/core/crypto/_fiat/field_poly1305/field.odin b/core/crypto/_fiat/field_poly1305/field.odin index c50a56b0c..b12046858 100644 --- a/core/crypto/_fiat/field_poly1305/field.odin +++ b/core/crypto/_fiat/field_poly1305/field.odin @@ -7,13 +7,13 @@ import "core:mem" fe_relax_cast :: #force_inline proc "contextless" ( arg1: ^Tight_Field_Element, ) -> ^Loose_Field_Element { - return transmute(^Loose_Field_Element)(arg1) + return (^Loose_Field_Element)(arg1) } fe_tighten_cast :: #force_inline proc "contextless" ( arg1: ^Loose_Field_Element, ) -> ^Tight_Field_Element { - return transmute(^Tight_Field_Element)(arg1) + return (^Tight_Field_Element)(arg1) } fe_from_bytes :: #force_inline proc "contextless" ( diff --git a/core/crypto/kmac/kmac.odin b/core/crypto/kmac/kmac.odin index e5be6f91b..711f459b3 100644 --- a/core/crypto/kmac/kmac.odin +++ b/core/crypto/kmac/kmac.odin @@ -61,7 +61,7 @@ init_256 :: proc(ctx: ^Context, key, domain_sep: []byte) { update :: proc(ctx: ^Context, data: []byte) { assert(ctx.is_initialized) - shake.write(transmute(^shake.Context)(ctx), data) + shake.write((^shake.Context)(ctx), data) } // final finalizes the Context, writes the tag to dst, and calls reset @@ -75,7 +75,7 @@ final :: proc(ctx: ^Context, dst: []byte) { panic("crypto/kmac: invalid KMAC tag_size, too short") } - _sha3.final_cshake(transmute(^_sha3.Context)(ctx), dst) + _sha3.final_cshake((^_sha3.Context)(ctx), dst) } // clone clones the Context other into ctx. @@ -84,7 +84,7 @@ clone :: proc(ctx, other: ^Context) { return } - shake.clone(transmute(^shake.Context)(ctx), transmute(^shake.Context)(other)) + shake.clone((^shake.Context)(ctx), (^shake.Context)(other)) } // reset sanitizes the Context. The Context must be re-initialized to @@ -94,7 +94,7 @@ reset :: proc(ctx: ^Context) { return } - shake.reset(transmute(^shake.Context)(ctx)) + shake.reset((^shake.Context)(ctx)) } @(private) @@ -107,7 +107,7 @@ _init_kmac :: proc(ctx: ^Context, key, s: []byte, sec_strength: int) { panic("crypto/kmac: invalid KMAC key, too short") } - ctx_ := transmute(^_sha3.Context)(ctx) + ctx_ := (^_sha3.Context)(ctx) _sha3.init_cshake(ctx_, N_KMAC, s, sec_strength) _sha3.bytepad(ctx_, [][]byte{key}, _sha3.rate_cshake(sec_strength)) } diff --git a/core/crypto/legacy/keccak/keccak.odin b/core/crypto/legacy/keccak/keccak.odin index 7813a1ab4..6ca66b7ca 100644 --- a/core/crypto/legacy/keccak/keccak.odin +++ b/core/crypto/legacy/keccak/keccak.odin @@ -66,12 +66,12 @@ init_512 :: proc(ctx: ^Context) { @(private) _init :: proc(ctx: ^Context) { ctx.dsbyte = _sha3.DS_KECCAK - _sha3.init(transmute(^_sha3.Context)(ctx)) + _sha3.init((^_sha3.Context)(ctx)) } // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { - _sha3.update(transmute(^_sha3.Context)(ctx), data) + _sha3.update((^_sha3.Context)(ctx), data) } // final finalizes the Context, writes the digest to hash, and calls @@ -80,16 +80,16 @@ update :: proc(ctx: ^Context, data: []byte) { // Iff finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { - _sha3.final(transmute(^_sha3.Context)(ctx), hash, finalize_clone) + _sha3.final((^_sha3.Context)(ctx), hash, finalize_clone) } // clone clones the Context other into ctx. clone :: proc(ctx, other: ^Context) { - _sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other)) + _sha3.clone((^_sha3.Context)(ctx), (^_sha3.Context)(other)) } // reset sanitizes the Context. The Context must be re-initialized to // be used again. reset :: proc(ctx: ^Context) { - _sha3.reset(transmute(^_sha3.Context)(ctx)) + _sha3.reset((^_sha3.Context)(ctx)) } diff --git a/core/crypto/ristretto255/ristretto255.odin b/core/crypto/ristretto255/ristretto255.odin index d1f2b6ee5..3a2307da0 100644 --- a/core/crypto/ristretto255/ristretto255.odin +++ b/core/crypto/ristretto255/ristretto255.odin @@ -112,7 +112,7 @@ ge_set_bytes :: proc "contextless" (ge: ^Group_Element, b: []byte) -> bool { return false } - b_ := transmute(^[32]byte)(raw_data(b)) + b_ := (^[32]byte)(raw_data(b)) s: field.Tight_Field_Element = --- defer field.fe_clear(&s) @@ -297,7 +297,7 @@ ge_bytes :: proc(ge: ^Group_Element, dst: []byte) { // 2. Return the 32-byte little-endian encoding of s. More // specifically, this is the encoding of the canonical // representation of s as an integer between 0 and p-1, inclusive. - dst_ := transmute(^[32]byte)(raw_data(dst)) + dst_ := (^[32]byte)(raw_data(dst)) field.fe_to_bytes(dst_, &tmp) field.fe_clear_vec([]^field.Tight_Field_Element{&u1, &u2, &tmp, &z_inv, &ix0, &iy0, &x, &y}) @@ -417,7 +417,7 @@ ge_is_identity :: proc(ge: ^Group_Element) -> int { @(private) ge_map :: proc "contextless" (ge: ^Group_Element, b: []byte) { - b_ := transmute(^[32]byte)(raw_data(b)) + b_ := (^[32]byte)(raw_data(b)) // The MAP function is defined on 32-byte strings as: // diff --git a/core/crypto/ristretto255/ristretto255_scalar.odin b/core/crypto/ristretto255/ristretto255_scalar.odin index f581e5963..1ecb490e0 100644 --- a/core/crypto/ristretto255/ristretto255_scalar.odin +++ b/core/crypto/ristretto255/ristretto255_scalar.odin @@ -46,7 +46,7 @@ sc_set_bytes_wide :: proc(sc: ^Scalar, b: []byte) { panic("crypto/ristretto255: invalid wide input size") } - b_ := transmute(^[WIDE_SCALAR_SIZE]byte)(raw_data(b)) + b_ := (^[WIDE_SCALAR_SIZE]byte)(raw_data(b)) grp.sc_set_bytes_wide(sc, b_) } diff --git a/core/crypto/sha3/sha3.odin b/core/crypto/sha3/sha3.odin index bc3e6e846..78057f1ca 100644 --- a/core/crypto/sha3/sha3.odin +++ b/core/crypto/sha3/sha3.odin @@ -68,12 +68,12 @@ init_512 :: proc(ctx: ^Context) { @(private) _init :: proc(ctx: ^Context) { ctx.dsbyte = _sha3.DS_SHA3 - _sha3.init(transmute(^_sha3.Context)(ctx)) + _sha3.init((^_sha3.Context)(ctx)) } // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { - _sha3.update(transmute(^_sha3.Context)(ctx), data) + _sha3.update((^_sha3.Context)(ctx), data) } // final finalizes the Context, writes the digest to hash, and calls @@ -82,16 +82,16 @@ update :: proc(ctx: ^Context, data: []byte) { // Iff finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { - _sha3.final(transmute(^_sha3.Context)(ctx), hash, finalize_clone) + _sha3.final((^_sha3.Context)(ctx), hash, finalize_clone) } // clone clones the Context other into ctx. clone :: proc(ctx, other: ^Context) { - _sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other)) + _sha3.clone((^_sha3.Context)(ctx), (^_sha3.Context)(other)) } // reset sanitizes the Context. The Context must be re-initialized to // be used again. reset :: proc(ctx: ^Context) { - _sha3.reset(transmute(^_sha3.Context)(ctx)) + _sha3.reset((^_sha3.Context)(ctx)) } diff --git a/core/crypto/shake/shake.odin b/core/crypto/shake/shake.odin index 7da427485..4160f4cf9 100644 --- a/core/crypto/shake/shake.odin +++ b/core/crypto/shake/shake.odin @@ -24,35 +24,35 @@ Context :: distinct _sha3.Context // init_128 initializes a Context for SHAKE128. init_128 :: proc(ctx: ^Context) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, nil, 128) + _sha3.init_cshake((^_sha3.Context)(ctx), nil, nil, 128) } // init_256 initializes a Context for SHAKE256. init_256 :: proc(ctx: ^Context) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, nil, 256) + _sha3.init_cshake((^_sha3.Context)(ctx), nil, nil, 256) } // init_cshake_128 initializes a Context for cSHAKE128. init_cshake_128 :: proc(ctx: ^Context, domain_sep: []byte) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, domain_sep, 128) + _sha3.init_cshake((^_sha3.Context)(ctx), nil, domain_sep, 128) } // init_cshake_256 initializes a Context for cSHAKE256. init_cshake_256 :: proc(ctx: ^Context, domain_sep: []byte) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), nil, domain_sep, 256) + _sha3.init_cshake((^_sha3.Context)(ctx), nil, domain_sep, 256) } // write writes more data into the SHAKE instance. This MUST not be called // after any reads have been done, and attempts to do so will panic. write :: proc(ctx: ^Context, data: []byte) { - _sha3.update(transmute(^_sha3.Context)(ctx), data) + _sha3.update((^_sha3.Context)(ctx), data) } // read reads output from the SHAKE instance. There is no practical upper // limit to the amount of data that can be read from SHAKE. After read has // been called one or more times, further calls to write will panic. read :: proc(ctx: ^Context, dst: []byte) { - ctx_ := transmute(^_sha3.Context)(ctx) + ctx_ := (^_sha3.Context)(ctx) if !ctx.is_finalized { _sha3.shake_xof(ctx_) } @@ -62,11 +62,11 @@ read :: proc(ctx: ^Context, dst: []byte) { // clone clones the Context other into ctx. clone :: proc(ctx, other: ^Context) { - _sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other)) + _sha3.clone((^_sha3.Context)(ctx), (^_sha3.Context)(other)) } // reset sanitizes the Context. The Context must be re-initialized to // be used again. reset :: proc(ctx: ^Context) { - _sha3.reset(transmute(^_sha3.Context)(ctx)) + _sha3.reset((^_sha3.Context)(ctx)) } diff --git a/core/crypto/tuplehash/tuplehash.odin b/core/crypto/tuplehash/tuplehash.odin index baba1ce59..ed0a3aa87 100644 --- a/core/crypto/tuplehash/tuplehash.odin +++ b/core/crypto/tuplehash/tuplehash.odin @@ -13,19 +13,19 @@ Context :: distinct _sha3.Context // init_128 initializes a Context for TupleHash128 or TupleHashXOF128. init_128 :: proc(ctx: ^Context, domain_sep: []byte) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), N_TUPLEHASH, domain_sep, 128) + _sha3.init_cshake((^_sha3.Context)(ctx), N_TUPLEHASH, domain_sep, 128) } // init_256 initializes a Context for TupleHash256 or TupleHashXOF256. init_256 :: proc(ctx: ^Context, domain_sep: []byte) { - _sha3.init_cshake(transmute(^_sha3.Context)(ctx), N_TUPLEHASH, domain_sep, 256) + _sha3.init_cshake((^_sha3.Context)(ctx), N_TUPLEHASH, domain_sep, 256) } // write_element writes a tuple element into the TupleHash or TupleHashXOF // instance. This MUST not be called after any reads have been done, and // any attempts to do so will panic. write_element :: proc(ctx: ^Context, data: []byte) { - _, _ = _sha3.encode_string(transmute(^_sha3.Context)(ctx), data) + _, _ = _sha3.encode_string((^_sha3.Context)(ctx), data) } // final finalizes the Context, writes the digest to hash, and calls @@ -34,7 +34,7 @@ write_element :: proc(ctx: ^Context, data: []byte) { // Iff finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { - _sha3.final_cshake(transmute(^_sha3.Context)(ctx), hash, finalize_clone) + _sha3.final_cshake((^_sha3.Context)(ctx), hash, finalize_clone) } // read reads output from the TupleHashXOF instance. There is no practical @@ -42,7 +42,7 @@ final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { // After read has been called one or more times, further calls to // write_element will panic. read :: proc(ctx: ^Context, dst: []byte) { - ctx_ := transmute(^_sha3.Context)(ctx) + ctx_ := (^_sha3.Context)(ctx) if !ctx.is_finalized { _sha3.encode_byte_len(ctx_, 0, false) // right_encode _sha3.shake_xof(ctx_) @@ -53,13 +53,13 @@ read :: proc(ctx: ^Context, dst: []byte) { // clone clones the Context other into ctx. clone :: proc(ctx, other: ^Context) { - _sha3.clone(transmute(^_sha3.Context)(ctx), transmute(^_sha3.Context)(other)) + _sha3.clone((^_sha3.Context)(ctx), (^_sha3.Context)(other)) } // reset sanitizes the Context. The Context must be re-initialized to // be used again. reset :: proc(ctx: ^Context) { - _sha3.reset(transmute(^_sha3.Context)(ctx)) + _sha3.reset((^_sha3.Context)(ctx)) } @(private) diff --git a/core/image/qoi/qoi.odin b/core/image/qoi/qoi.odin index 061943f68..15ed449da 100644 --- a/core/image/qoi/qoi.odin +++ b/core/image/qoi/qoi.odin @@ -139,15 +139,13 @@ save_to_buffer :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{} } else { // Write RGB literal output.buf[written] = u8(QOI_Opcode_Tag.RGB) - pix_bytes := transmute([4]u8)pix - copy(output.buf[written + 1:], pix_bytes[:3]) + copy(output.buf[written + 1:], pix[:3]) written += 4 } } else { // Write RGBA literal output.buf[written] = u8(QOI_Opcode_Tag.RGBA) - pix_bytes := transmute([4]u8)pix - copy(output.buf[written + 1:], pix_bytes[:]) + copy(output.buf[written + 1:], pix[:]) written += 5 } } diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index b1fde77b3..75a1f6a29 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -883,8 +883,8 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } defer _unix_free(path_ptr) - path_cstr := transmute(cstring)path_ptr - path = strings.clone( string(path_cstr) ) + path_cstr := cast(cstring)path_ptr + path = strings.clone(string(path_cstr)) return path, ERROR_NONE } diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 8fe179478..97165b262 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -648,8 +648,8 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } defer _unix_free(path_ptr) - path_cstr := transmute(cstring)path_ptr - path = strings.clone( string(path_cstr) ) + + path = strings.clone(string(cstring(path_ptr))) return path, ERROR_NONE } diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 545349bc5..ebc1b3600 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -890,8 +890,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } defer _unix_free(path_ptr) - path_cstr := transmute(cstring)path_ptr - path = strings.clone( string(path_cstr) ) + path = strings.clone(string(cstring(path_ptr))) return path, ERROR_NONE } diff --git a/core/sys/info/cpu_intel.odin b/core/sys/info/cpu_intel.odin index 63af853d0..73d4c15e7 100644 --- a/core/sys/info/cpu_intel.odin +++ b/core/sys/info/cpu_intel.odin @@ -117,7 +117,7 @@ init_cpu_name :: proc "c" () { return } - _buf := transmute(^[0x12]u32)&_cpu_name_buf + _buf := (^[0x12]u32)(&_cpu_name_buf) _buf[ 0], _buf[ 1], _buf[ 2], _buf[ 3] = cpuid(0x8000_0002, 0) _buf[ 4], _buf[ 5], _buf[ 6], _buf[ 7] = cpuid(0x8000_0003, 0) _buf[ 8], _buf[ 9], _buf[10], _buf[11] = cpuid(0x8000_0004, 0) diff --git a/core/sys/linux/wrappers.odin b/core/sys/linux/wrappers.odin index 13073315d..95c818b9d 100644 --- a/core/sys/linux/wrappers.odin +++ b/core/sys/linux/wrappers.odin @@ -85,13 +85,13 @@ dirent_iterate_buf :: proc "contextless" (buf: []u8, offs: ^int) -> (d: ^Dirent, /// Obtain the name of dirent as a string /// The lifetime of the string is bound to the lifetime of the provided dirent structure dirent_name :: proc "contextless" (dirent: ^Dirent) -> string #no_bounds_check { - str := transmute([^]u8) &dirent.name + str := ([^]u8)(&dirent.name) // Note(flysand): The string size calculated above applies only to the ideal case // we subtract 1 byte from the string size, because a null terminator is guaranteed // to be present. But! That said, the dirents are aligned to 8 bytes and the padding // between the null terminator and the start of the next struct may be not initialized // which means we also have to scan these garbage bytes. - str_size := (cast(int) dirent.reclen) - 1 - cast(int) offset_of(Dirent, name) + str_size := int(dirent.reclen) - 1 - cast(int)offset_of(Dirent, name) // This skips *only* over the garbage, since if we're not garbage we're at nul terminator, // which skips this loop for str[str_size] != 0 { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2fa491417..45500e79a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3396,7 +3396,7 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forb ) { gbString oper_str = expr_to_string(x->expr); gbString to_type = type_to_string(dst_exact); - error(x->expr, "Unneeded cast of `%s` to identical type `%s`", oper_str, to_type); + error(x->expr, "Unneeded cast of '%s' to identical type '%s'", oper_str, to_type); gb_string_free(oper_str); gb_string_free(to_type); } @@ -3406,22 +3406,13 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forb x->type = type; } -gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t) { +gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t, bool forbid_identical = false) { if (!is_operand_value(*o)) { error(o->expr, "'transmute' can only be applied to values"); o->mode = Addressing_Invalid; return false; } - // if (o->mode == Addressing_Constant) { - // gbString expr_str = expr_to_string(o->expr); - // error(o->expr, "Cannot transmute a constant expression: '%s'", expr_str); - // gb_string_free(expr_str); - // o->mode = Addressing_Invalid; - // o->expr = node; - // return false; - // } - Type *src_t = o->type; Type *dst_t = t; Type *src_bt = base_type(src_t); @@ -3504,6 +3495,29 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type return true; } } + } else { + // If we check polymorphic procedures, we risk erring on + // identical casts that cannot be foreseen or otherwise + // forbidden, so just skip them. + if (forbid_identical && check_vet_flags(c) & VetFlag_Cast && + (c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig))) { + bool is_runtime = false; + if (c->pkg && (c->pkg->kind == Package_Runtime || c->pkg->kind == Package_Builtin)) { + is_runtime = true; + } + if (are_types_identical(src_t, dst_t) && !is_runtime) { + gbString oper_str = expr_to_string(o->expr); + gbString to_type = type_to_string(dst_t); + error(o->expr, "Unneeded transmute of '%s' to identical type '%s'", oper_str, to_type); + gb_string_free(oper_str); + gb_string_free(to_type); + } else if (is_type_internally_pointer_like(src_t) && + is_type_internally_pointer_like(dst_t)) { + gbString to_type = type_to_string(dst_t); + error(o->expr, "Use of 'transmute' where 'cast' would be preferred since the types are pointer-like", to_type); + gb_string_free(to_type); + } + } } o->mode = Addressing_Value; @@ -10734,7 +10748,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast if (o->mode != Addressing_Invalid) { switch (tc->token.kind) { case Token_transmute: - check_transmute(c, node, o, type); + check_transmute(c, node, o, type, true); break; case Token_cast: check_cast(c, o, type, true); -- cgit v1.2.3 From e46d772b6d01d06d7186438cadb61a0a30f17371 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 29 Jun 2024 12:13:41 +0100 Subject: Add check for integer casts --- src/check_expr.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 45500e79a..6b11a9d08 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3505,17 +3505,24 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type if (c->pkg && (c->pkg->kind == Package_Runtime || c->pkg->kind == Package_Builtin)) { is_runtime = true; } - if (are_types_identical(src_t, dst_t) && !is_runtime) { - gbString oper_str = expr_to_string(o->expr); - gbString to_type = type_to_string(dst_t); - error(o->expr, "Unneeded transmute of '%s' to identical type '%s'", oper_str, to_type); - gb_string_free(oper_str); - gb_string_free(to_type); + if (are_types_identical(src_t, dst_t)) { + if (!is_runtime) { + gbString oper_str = expr_to_string(o->expr); + gbString to_type = type_to_string(dst_t); + error(o->expr, "Unneeded transmute of '%s' to identical type '%s'", oper_str, to_type); + gb_string_free(oper_str); + gb_string_free(to_type); + } } else if (is_type_internally_pointer_like(src_t) && is_type_internally_pointer_like(dst_t)) { - gbString to_type = type_to_string(dst_t); - error(o->expr, "Use of 'transmute' where 'cast' would be preferred since the types are pointer-like", to_type); + error(o->expr, "Use of 'transmute' where 'cast' would be preferred since the types are pointer-like"); + } else if (is_type_integer(src_t) && is_type_integer(dst_t) && + types_have_same_internal_endian(src_t, dst_t)) { + gbString oper_type = type_to_string(src_t); + gbString to_type = type_to_string(dst_t); + error(o->expr, "Use of 'transmute' where 'cast' would be preferred since both are integers of the same endianness, from '%s' to '%s'", oper_type, to_type); gb_string_free(to_type); + gb_string_free(oper_type); } } } -- cgit v1.2.3 From c88a1bef91c56e8b2732077965381156032805d3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 29 Jun 2024 12:40:04 +0100 Subject: Add another `-vet-cast` check --- base/runtime/internal.odin | 1 + core/encoding/uuid/stamping.odin | 2 +- core/net/addr.odin | 7 +++---- core/net/socket_linux.odin | 4 ++-- src/check_expr.cpp | 22 +++++++++++----------- 5 files changed, 18 insertions(+), 18 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/base/runtime/internal.odin b/base/runtime/internal.odin index 203ee2873..1a97ade09 100644 --- a/base/runtime/internal.odin +++ b/base/runtime/internal.odin @@ -1,3 +1,4 @@ +//+vet !cast package runtime import "base:intrinsics" diff --git a/core/encoding/uuid/stamping.odin b/core/encoding/uuid/stamping.odin index 0c07725c3..3ca61fe44 100644 --- a/core/encoding/uuid/stamping.odin +++ b/core/encoding/uuid/stamping.odin @@ -41,7 +41,7 @@ Returns: - result: A valid version 8 UUID. */ stamp_v8_array :: proc(array: [16]u8) -> (result: Identifier) { - result = transmute(Identifier)array + result = Identifier(array) result[VERSION_BYTE_INDEX] &= 0x0F result[VERSION_BYTE_INDEX] |= 0x80 diff --git a/core/net/addr.odin b/core/net/addr.odin index c01724d99..eed3fb3b9 100644 --- a/core/net/addr.odin +++ b/core/net/addr.odin @@ -370,7 +370,7 @@ parse_ip6_address :: proc(address_and_maybe_port: string) -> (addr: IP6_Address, val |= u16(ipv4[3]) piece_values[7] = u16be(val) } - return transmute(IP6_Address)piece_values, true + return IP6_Address(piece_values), true } /* @@ -522,10 +522,9 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) -> run := Zero_Run{-1, -1} best := Zero_Run{-1, -1} - addr := transmute([8]u16be)v last := u16be(1) - for val, i in addr { + for val, i in v { /* If we encounter adjacent zeroes, then start a new run if not already in one. Also remember the rightmost index regardless, because it'll be the new @@ -559,7 +558,7 @@ address_to_string :: proc(addr: Address, allocator := context.temp_allocator) -> last = val } - for val, i in addr { + for val, i in v { if best.start == i || best.end == i { // For the left and right side of the best zero run, print a `:`. fmt.sbprint(&b, ":") diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index a4d75b92b..dc960a5fb 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -80,14 +80,14 @@ _unwrap_os_addr :: proc "contextless" (endpoint: Endpoint)->(linux.Sock_Addr_Any ipv4 = { sin_family = .INET, sin_port = u16be(endpoint.port), - sin_addr = transmute([4]u8) endpoint.address.(IP4_Address), + sin_addr = ([4]u8)(endpoint.address.(IP4_Address)), }, } case IP6_Address: return { ipv6 = { sin6_port = u16be(endpoint.port), - sin6_addr = transmute([16]u8) endpoint.address.(IP6_Address), + sin6_addr = transmute([16]u8)endpoint.address.(IP6_Address), sin6_family = .INET6, }, } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6b11a9d08..7107c5712 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3501,21 +3501,21 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type // forbidden, so just skip them. if (forbid_identical && check_vet_flags(c) & VetFlag_Cast && (c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig))) { - bool is_runtime = false; - if (c->pkg && (c->pkg->kind == Package_Runtime || c->pkg->kind == Package_Builtin)) { - is_runtime = true; - } if (are_types_identical(src_t, dst_t)) { - if (!is_runtime) { - gbString oper_str = expr_to_string(o->expr); - gbString to_type = type_to_string(dst_t); - error(o->expr, "Unneeded transmute of '%s' to identical type '%s'", oper_str, to_type); - gb_string_free(oper_str); - gb_string_free(to_type); - } + gbString oper_str = expr_to_string(o->expr); + gbString to_type = type_to_string(dst_t); + error(o->expr, "Unneeded transmute of '%s' to identical type '%s'", oper_str, to_type); + gb_string_free(oper_str); + gb_string_free(to_type); } else if (is_type_internally_pointer_like(src_t) && is_type_internally_pointer_like(dst_t)) { error(o->expr, "Use of 'transmute' where 'cast' would be preferred since the types are pointer-like"); + } else if (are_types_identical(src_bt, dst_bt)) { + gbString oper_str = expr_to_string(o->expr); + gbString to_type = type_to_string(dst_t); + error(o->expr, "Unneeded transmute of '%s' to identical type '%s'", oper_str, to_type); + gb_string_free(oper_str); + gb_string_free(to_type); } else if (is_type_integer(src_t) && is_type_integer(dst_t) && types_have_same_internal_endian(src_t, dst_t)) { gbString oper_type = type_to_string(src_t); -- cgit v1.2.3 From e0face1ac87d34738751bbdb8c29f32bb89b544d Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Sun, 30 Jun 2024 20:36:51 +0200 Subject: Make types like bit_set[$T] have their upper and lower bits overwritten by upper/lower from the source types when checking if polymorphic type is assignable. This fixes an issue where an i8 was always generated for bit_sets with generic elements, because it couldn't figure out upper/lower when check_bit_set_type was run. Fixes #2860 --- src/check_expr.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 891378b99..b9697a6e8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1435,6 +1435,16 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T if (!is_polymorphic_type_assignable(c, poly->BitSet.elem, source->BitSet.elem, true, modify_type)) { return false; } + + // For generic types like bit_set[$T] the upper and lower of the poly type will be zeroes since + // it could not figure that stuff out when the poly type was created. + if (poly->BitSet.upper == 0 && modify_type) { + poly->BitSet.upper = source->BitSet.upper; + } + if (poly->BitSet.lower == 0 && modify_type) { + poly->BitSet.lower = source->BitSet.lower; + } + if (poly->BitSet.underlying == nullptr) { if (modify_type) { poly->BitSet.underlying = source->BitSet.underlying; -- cgit v1.2.3 From 11617af8f5434c2bbe712d8e71339debcad078ed Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 1 Jul 2024 11:34:50 +0100 Subject: Add support for `make(#soa[]T)` etc --- base/runtime/core_builtin.odin | 5 +++ src/check_expr.cpp | 79 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index 4601bca9d..a549ca2ae 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -364,6 +364,11 @@ make :: proc{ make_dynamic_array_len_cap, make_map, make_multi_pointer, + + make_soa_slice, + make_soa_dynamic_array, + make_soa_dynamic_array_len, + make_soa_dynamic_array_len_cap, } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e11014a70..c07a3b248 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6800,9 +6800,71 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, if (procs.count > 0) { error_line("Did you mean to use one of the following:\n"); } + + // Try to reduce the list further for `$T: typeid` like parameters + bool *possibly_ignore = gb_alloc_array(temporary_allocator(), bool, procs.count); + isize possibly_ignore_set = 0; + + if (true) { + // NOTE(bill): This currently only checks for #soa types + for_array(i, procs) { + Entity *proc = procs[i]; + Type *t = base_type(proc->type); + if (t->kind != Type_Proc) continue; + + TypeProc *pt = &t->Proc; + if (pt->param_count == 0) { + continue; + } + + for_array(j, pt->params->Tuple.variables) { + Entity *v = pt->params->Tuple.variables[j]; + if (v->kind != Entity_TypeName) { + continue; + } + + Type *dst_t = base_type(v->type); + while (dst_t->kind == Type_Generic && dst_t->Generic.specialized) { + dst_t = dst_t->Generic.specialized; + } + + if (j >= positional_operands.count) { + continue; + } + Operand const &o = positional_operands[j]; + if (o.mode != Addressing_Type) { + continue; + } + Type *t = base_type(o.type); + if (t->kind == dst_t->kind) { + continue; + } + Type *st = base_type(type_deref(o.type)); + Type *dt = base_type(type_deref(dst_t)); + if (st->kind == dt->kind) { + continue; + } + if (is_type_soa_struct(st)) { + possibly_ignore[i] = true; + possibly_ignore_set += 1; + continue; + } + } + } + } + + if (possibly_ignore_set == procs.count) { + possibly_ignore_set = 0; + } + + isize max_name_length = 0; isize max_type_length = 0; - for (Entity *proc : procs) { + for_array(i, procs) { + if (possibly_ignore_set != 0 && possibly_ignore[i]) { + continue; + } + Entity *proc = procs[i]; Type *t = base_type(proc->type); if (t == t_invalid) continue; String prefix = {}; @@ -6832,7 +6894,11 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } spaces[max_spaces] = 0; - for (Entity *proc : procs) { + for_array(i, procs) { + if (possibly_ignore_set != 0 && possibly_ignore[i]) { + continue; + } + Entity *proc = procs[i]; TokenPos pos = proc->token.pos; Type *t = base_type(proc->type); if (t == t_invalid) continue; @@ -11414,6 +11480,9 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; case_ast_node(pt, PointerType, node); + if (pt->tag) { + str = write_expr_to_string(str, pt->tag, false); + } str = gb_string_append_rune(str, '^'); str = write_expr_to_string(str, pt->type, shorthand); case_end; @@ -11424,6 +11493,9 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; case_ast_node(at, ArrayType, node); + if (at->tag) { + str = write_expr_to_string(str, at->tag, false); + } str = gb_string_append_rune(str, '['); if (at->count != nullptr && at->count->kind == Ast_UnaryExpr && @@ -11437,6 +11509,9 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; case_ast_node(at, DynamicArrayType, node); + if (at->tag) { + str = write_expr_to_string(str, at->tag, false); + } str = gb_string_appendc(str, "[dynamic]"); str = write_expr_to_string(str, at->elem, shorthand); case_end; -- cgit v1.2.3 From 4086a62167a6351a3cef32805abf1a7693bd16f7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 1 Jul 2024 11:50:35 +0100 Subject: Fix showing error when not meant to --- src/check_expr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c07a3b248..8880452e4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6168,7 +6168,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A Type *t = elem; if (is_type_polymorphic(t)) { - error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input %s", type_to_string(final_proc_type)); + if (show_error) { + error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input %s", type_to_string(final_proc_type)); + } err = CallArgumentError_AmbiguousPolymorphicVariadic; } -- cgit v1.2.3 From 42ff7111145e5264ce708edadd69b8c031106c97 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 1 Jul 2024 12:22:18 +0100 Subject: Fix #3515 --- src/check_expr.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8880452e4..b6e5bc222 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9123,12 +9123,16 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * type = nullptr; // [?]Type - if (type_expr->kind == Ast_ArrayType && type_expr->ArrayType.count != nullptr) { + if (type_expr->kind == Ast_ArrayType) { Ast *count = type_expr->ArrayType.count; - if (count->kind == Ast_UnaryExpr && - count->UnaryExpr.op.kind == Token_Question) { - type = alloc_type_array(check_type(c, type_expr->ArrayType.elem), -1); - is_to_be_determined_array_count = true; + if (count != nullptr) { + if (count->kind == Ast_UnaryExpr && + count->UnaryExpr.op.kind == Token_Question) { + type = alloc_type_array(check_type(c, type_expr->ArrayType.elem), -1); + is_to_be_determined_array_count = true; + } + } else { + type = alloc_type_slice(check_type(c, type_expr->ArrayType.elem)); } if (cl->elems.count > 0) { if (type_expr->ArrayType.tag != nullptr) { @@ -9141,8 +9145,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } } } - } - if (type_expr->kind == Ast_DynamicArrayType && type_expr->DynamicArrayType.tag != nullptr) { + } else if (type_expr->kind == Ast_DynamicArrayType && type_expr->DynamicArrayType.tag != nullptr) { if (cl->elems.count > 0) { Ast *tag = type_expr->DynamicArrayType.tag; GB_ASSERT(tag->kind == Ast_BasicDirective); @@ -9181,6 +9184,12 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (cl->elems.count == 0) { break; // NOTE(bill): No need to init } + + if (t->Struct.soa_kind != StructSoa_None) { + error(node, "#soa arrays are not supported for compound literals"); + break; + } + if (t->Struct.is_raw_union) { if (cl->elems.count > 0) { // NOTE: unions cannot be constant -- cgit v1.2.3 From a2b23de0a72ad34f09d11c88fcee4062a54b554e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 1 Jul 2024 12:24:46 +0100 Subject: Sanity check for a `nullptr` --- src/check_expr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b6e5bc222..2d0b9dfa9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6812,7 +6812,9 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, for_array(i, procs) { Entity *proc = procs[i]; Type *t = base_type(proc->type); - if (t->kind != Type_Proc) continue; + if (t == nullptr || t->kind != Type_Proc) { + continue; + } TypeProc *pt = &t->Proc; if (pt->param_count == 0) { -- cgit v1.2.3 From 657bc88535eb3b160d86fed5f5e5d0d6ea67c78c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 4 Jul 2024 13:48:52 +0100 Subject: Allow `x :: y when cond else proc(...){...}` --- src/check_decl.cpp | 234 +++++++++++++++++++++++++++++++++++------------------ src/check_expr.cpp | 22 ++++- src/checker.cpp | 12 +++ 3 files changed, 189 insertions(+), 79 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 3c4a4b3de..0f48c28e3 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -155,6 +155,154 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l } } + +gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_entity) { + // NOTE(bill): The original_entity's scope may not be same scope that it was inserted into + // e.g. file entity inserted into its package scope + String original_name = original_entity->token.string; + Scope *found_scope = nullptr; + Entity *found_entity = nullptr; + scope_lookup_parent(original_entity->scope, original_name, &found_scope, &found_entity); + if (found_scope == nullptr) { + return; + } + rw_mutex_lock(&found_scope->mutex); + defer (rw_mutex_unlock(&found_scope->mutex)); + + // IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the + // original entity was still used check checked, but the checking was only + // relying on "constant" data such as the Entity.type and Entity.Constant.value + // + // Therefore two things can be done: the type can be assigned to state that it + // has been "evaluated" and the variant data can be copied across + + string_map_set(&found_scope->elements, original_name, new_entity); + + original_entity->flags |= EntityFlag_Overridden; + original_entity->type = new_entity->type; + original_entity->aliased_of = new_entity; + + Ast *empty_ident = nullptr; + original_entity->identifier.compare_exchange_strong(empty_ident, new_entity->identifier); + + if (original_entity->identifier.load() != nullptr && + original_entity->identifier.load()->kind == Ast_Ident) { + original_entity->identifier.load()->Ident.entity = new_entity; + } + + // IMPORTANT NOTE(bill, 2021-04-10): copy only the variants + // This is most likely NEVER required, but it does not at all hurt to keep + isize offset = cast(u8 *)&original_entity->Dummy.start - cast(u8 *)original_entity; + isize size = gb_size_of(*original_entity) - offset; + gb_memmove(cast(u8 *)original_entity, cast(u8 *)new_entity, size); +} + + +gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d); + +gb_internal bool check_try_override_const_decl(CheckerContext *ctx, Entity *e, Entity *entity, Ast *init, Type *named_type) { + if (entity == nullptr) { + retry_proc_lit:; + init = unparen_expr(init); + if (init == nullptr) { + return false; + } + if (init->kind == Ast_TernaryWhenExpr) { + ast_node(we, TernaryWhenExpr, init); + if (we->cond == nullptr) { + return false; + } + if (we->cond->tav.value.kind != ExactValue_Bool) { + return false; + } + init = we->cond->tav.value.value_bool ? we->x : we->y; + goto retry_proc_lit; + } if (init->kind == Ast_ProcLit) { + // NOTE(bill, 2024-07-04): Override as a procedure entity because this could be within a `when` statement + e->kind = Entity_Procedure; + e->type = nullptr; + DeclInfo *d = decl_info_of_entity(e); + d->proc_lit = init; + check_proc_decl(ctx, e, d); + return true; + } + + return false; + } + switch (entity->kind) { + case Entity_TypeName: + // @TypeAliasingProblem + // NOTE(bill, 2022-02-03): This is used to solve the problem caused by type aliases + // being "confused" as constants + // + // A :: B + // C :: proc "c" (^A) + // B :: struct {x: C} + // + // A gets evaluated first, and then checks B. + // B then checks C. + // C then tries to check A which is unresolved but thought to be a constant. + // Therefore within C's check, A errs as "not a type". + // + // This is because a const declaration may or may not be a type and this cannot + // be determined from a syntactical standpoint. + // This check allows the compiler to override the entity to be checked as a type. + // + // There is no problem if B is prefixed with the `#type` helper enforcing at + // both a syntax and semantic level that B must be a type. + // + // A :: #type B + // + // This approach is not fool proof and can fail in case such as: + // + // X :: type_of(x) + // X :: Foo(int).Type + // + // Since even these kind of declarations may cause weird checking cycles. + // For the time being, these are going to be treated as an unfortunate error + // until there is a proper delaying system to try declaration again if they + // have failed. + + e->kind = Entity_TypeName; + check_type_decl(ctx, e, init, named_type); + return true; + case Entity_Builtin: + if (e->type != nullptr) { + return false; + } + e->kind = Entity_Builtin; + e->Builtin.id = entity->Builtin.id; + e->type = t_invalid; + return true; + case Entity_ProcGroup: + // NOTE(bill, 2020-06-10): It is better to just clone the contents than overriding the entity in the scope + // Thank goodness I made entities a tagged union to allow for this implace patching + e->kind = Entity_ProcGroup; + e->ProcGroup.entities = array_clone(heap_allocator(), entity->ProcGroup.entities); + return true; + } + + if (e->type != nullptr && entity->type != nullptr) { + Operand x = {}; + x.type = entity->type; + x.mode = Addressing_Variable; + if (!check_is_assignable_to(ctx, &x, e->type)) { + return false; + } + } + + // NOTE(bill): Override aliased entity + switch (entity->kind) { + case Entity_ProcGroup: + case Entity_Procedure: + case Entity_LibraryName: + case Entity_ImportName: + override_entity_in_scope(e, entity); + return true; + } + return false; +} + gb_internal void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) { if (operand->mode == Addressing_Invalid || operand->type == t_invalid || @@ -165,6 +313,13 @@ gb_internal void check_init_constant(CheckerContext *ctx, Entity *e, Operand *op return; } + if (operand->mode != Addressing_Constant) { + Entity *entity = entity_of_node(operand->expr); + if (check_try_override_const_decl(ctx, e, entity, operand->expr, nullptr)) { + return; + } + } + if (operand->mode != Addressing_Constant) { gbString str = expr_to_string(operand->expr); error(operand->expr, "'%s' is not a compile-time known constant", str); @@ -373,49 +528,6 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, } -gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_entity) { - // NOTE(bill): The original_entity's scope may not be same scope that it was inserted into - // e.g. file entity inserted into its package scope - String original_name = original_entity->token.string; - Scope *found_scope = nullptr; - Entity *found_entity = nullptr; - scope_lookup_parent(original_entity->scope, original_name, &found_scope, &found_entity); - if (found_scope == nullptr) { - return; - } - rw_mutex_lock(&found_scope->mutex); - defer (rw_mutex_unlock(&found_scope->mutex)); - - // IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the - // original entity was still used check checked, but the checking was only - // relying on "constant" data such as the Entity.type and Entity.Constant.value - // - // Therefore two things can be done: the type can be assigned to state that it - // has been "evaluated" and the variant data can be copied across - - string_map_set(&found_scope->elements, original_name, new_entity); - - original_entity->flags |= EntityFlag_Overridden; - original_entity->type = new_entity->type; - original_entity->aliased_of = new_entity; - - Ast *empty_ident = nullptr; - original_entity->identifier.compare_exchange_strong(empty_ident, new_entity->identifier); - - if (original_entity->identifier.load() != nullptr && - original_entity->identifier.load()->kind == Ast_Ident) { - original_entity->identifier.load()->Ident.entity = new_entity; - } - - // IMPORTANT NOTE(bill, 2021-04-10): copy only the variants - // This is most likely NEVER required, but it does not at all hurt to keep - isize offset = cast(u8 *)&original_entity->Dummy.start - cast(u8 *)original_entity; - isize size = gb_size_of(*original_entity) - offset; - gb_memmove(cast(u8 *)original_entity, cast(u8 *)new_entity, size); -} - - - gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Type *named_type) { GB_ASSERT(e->type == nullptr); GB_ASSERT(e->kind == Entity_Constant); @@ -441,41 +553,7 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr if (init != nullptr) { Entity *entity = check_entity_from_ident_or_selector(ctx, init, false); - if (entity != nullptr && entity->kind == Entity_TypeName) { - // @TypeAliasingProblem - // NOTE(bill, 2022-02-03): This is used to solve the problem caused by type aliases - // being "confused" as constants - // - // A :: B - // C :: proc "c" (^A) - // B :: struct {x: C} - // - // A gets evaluated first, and then checks B. - // B then checks C. - // C then tries to check A which is unresolved but thought to be a constant. - // Therefore within C's check, A errs as "not a type". - // - // This is because a const declaration may or may not be a type and this cannot - // be determined from a syntactical standpoint. - // This check allows the compiler to override the entity to be checked as a type. - // - // There is no problem if B is prefixed with the `#type` helper enforcing at - // both a syntax and semantic level that B must be a type. - // - // A :: #type B - // - // This approach is not fool proof and can fail in case such as: - // - // X :: type_of(x) - // X :: Foo(int).Type - // - // Since even these kind of declarations may cause weird checking cycles. - // For the time being, these are going to be treated as an unfortunate error - // until there is a proper delaying system to try declaration again if they - // have failed. - - e->kind = Entity_TypeName; - check_type_decl(ctx, e, init, named_type); + if (check_try_override_const_decl(ctx, e, entity, init, named_type)) { return; } entity = nullptr; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2d0b9dfa9..af5a9c521 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4968,7 +4968,27 @@ gb_internal bool is_entity_declared_for_selector(Entity *entity, Scope *import_s // NOTE(bill, 2022-02-03): see `check_const_decl` for why it exists reasoning gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *node, bool ident_only) { - if (node->kind == Ast_Ident) { + if (node == nullptr) { + return nullptr; + } + if (node->kind == Ast_TernaryWhenExpr) { + ast_node(we, TernaryWhenExpr, node); + if (we->cond == nullptr) { + return nullptr; + } + if (we->cond->tav.mode != Addressing_Constant) { + return nullptr; + } + if (we->cond->tav.value.kind != ExactValue_Bool) { + return nullptr; + } + if (we->cond->tav.value.value_bool) { + return check_entity_from_ident_or_selector(c, we->x, ident_only); + } else { + Entity *e = check_entity_from_ident_or_selector(c, we->y, ident_only); + return e; + } + } else if (node->kind == Ast_Ident) { String name = node->Ident.token.string; return scope_lookup(c->scope, name); } else if (!ident_only) if (node->kind == Ast_SelectorExpr) { diff --git a/src/checker.cpp b/src/checker.cpp index deee93dcc..503494c76 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1470,6 +1470,7 @@ gb_internal Entity *implicit_entity_of_node(Ast *clause) { } gb_internal Entity *entity_of_node(Ast *expr) { +retry:; expr = unparen_expr(expr); switch (expr->kind) { case_ast_node(ident, Ident, expr); @@ -1490,6 +1491,17 @@ gb_internal Entity *entity_of_node(Ast *expr) { case_ast_node(ce, CallExpr, expr); return ce->entity_procedure_of; case_end; + + case_ast_node(we, TernaryWhenExpr, expr); + if (we->cond == nullptr) { + break; + } + if (we->cond->tav.value.kind != ExactValue_Bool) { + break; + } + expr = we->cond->tav.value.value_bool ? we->x : we->y; + goto retry; + case_end; } return nullptr; } -- cgit v1.2.3 From bf711b282d49ce29c60fc31106a0dd640429e0b8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 4 Jul 2024 13:58:36 +0100 Subject: Remove `when` check in `check_entity_from_ident_or_selector` --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index af5a9c521..20b83c06d 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4971,7 +4971,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * if (node == nullptr) { return nullptr; } - if (node->kind == Ast_TernaryWhenExpr) { + /*if (node->kind == Ast_TernaryWhenExpr) { ast_node(we, TernaryWhenExpr, node); if (we->cond == nullptr) { return nullptr; @@ -4988,7 +4988,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * Entity *e = check_entity_from_ident_or_selector(c, we->y, ident_only); return e; } - } else if (node->kind == Ast_Ident) { + } else */if (node->kind == Ast_Ident) { String name = node->Ident.token.string; return scope_lookup(c->scope, name); } else if (!ident_only) if (node->kind == Ast_SelectorExpr) { -- cgit v1.2.3 From 77d64a54618fbdca2fd3f1be1f2719ddde3b463f Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sat, 6 Jul 2024 15:32:17 -0400 Subject: Forbid `$T=` parameter from crashing compiler Fixes #3883 --- src/check_expr.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 20b83c06d..782f60fda 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7185,6 +7185,8 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O Array operands = {}; defer (array_free(&operands)); + CallArgumentError err = CallArgumentError_None; + bool named_fields = false; { // NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves @@ -7202,6 +7204,11 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O Ast *arg = ce->args[i]; ast_node(fv, FieldValue, arg); + if (fv->value == nullptr) { + error(fv->eq, "Expected a value"); + err = CallArgumentError_InvalidFieldValue; + continue; + } if (fv->field->kind == Ast_Ident) { String name = fv->field->Ident.token.string; isize index = lookup_polymorphic_record_parameter(original_type, name); @@ -7240,7 +7247,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O } - CallArgumentError err = CallArgumentError_None; + if (err != 0) { + operand->mode = Addressing_Invalid; + return err; + } TypeTuple *tuple = get_record_polymorphic_params(original_type); isize param_count = tuple->variables.count; -- cgit v1.2.3 From 1fce5791a15d3133ee30e391a3558f3e806f9a5a Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 9 Jul 2024 19:33:25 +0200 Subject: fix require/enable target feature attribute on poly procs --- src/check_expr.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 782f60fda..bf55ffed7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -548,13 +548,15 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E final_proc_type->Proc.is_poly_specialized = true; final_proc_type->Proc.is_polymorphic = true; - final_proc_type->Proc.variadic = src->Proc.variadic; - final_proc_type->Proc.require_results = src->Proc.require_results; - final_proc_type->Proc.c_vararg = src->Proc.c_vararg; - final_proc_type->Proc.has_named_results = src->Proc.has_named_results; - final_proc_type->Proc.diverging = src->Proc.diverging; - final_proc_type->Proc.return_by_pointer = src->Proc.return_by_pointer; - final_proc_type->Proc.optional_ok = src->Proc.optional_ok; + final_proc_type->Proc.variadic = src->Proc.variadic; + final_proc_type->Proc.require_results = src->Proc.require_results; + final_proc_type->Proc.c_vararg = src->Proc.c_vararg; + final_proc_type->Proc.has_named_results = src->Proc.has_named_results; + final_proc_type->Proc.diverging = src->Proc.diverging; + final_proc_type->Proc.return_by_pointer = src->Proc.return_by_pointer; + final_proc_type->Proc.optional_ok = src->Proc.optional_ok; + final_proc_type->Proc.enable_target_feature = src->Proc.enable_target_feature; + final_proc_type->Proc.require_target_feature = src->Proc.require_target_feature; for (isize i = 0; i < operands.count; i++) { -- cgit v1.2.3 From 40625b24e2f08a20cafefc10bf4d13db9a3a93cc Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 9 Jul 2024 19:49:12 +0200 Subject: fix optimization mode, cold, and disabled not being applied to poly procs --- src/check_expr.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 782f60fda..799650656 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -587,6 +587,16 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E entity->file = base_entity->file; entity->pkg = base_entity->pkg; entity->flags = 0; + + entity->Procedure.optimization_mode = base_entity->Procedure.optimization_mode; + + if (base_entity->flags & EntityFlag_Cold) { + entity->flags |= EntityFlag_Cold; + } + if (base_entity->flags & EntityFlag_Disabled) { + entity->flags |= EntityFlag_Disabled; + } + d->entity = entity; AstFile *file = nullptr; -- cgit v1.2.3 From edc793d7c123a38826860ef72684308902a7012c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Jul 2024 11:39:05 +0100 Subject: Add `#no_capture args: ..T` to reuse the backing array stack memory --- core/fmt/fmt.odin | 58 +++++++++++++++++++++++------------------------ core/fmt/fmt_js.odin | 24 ++++++++++---------- core/fmt/fmt_os.odin | 24 ++++++++++---------- src/check_expr.cpp | 17 ++++++++++++++ src/check_type.cpp | 17 ++++++++++++++ src/checker.cpp | 1 + src/checker.hpp | 7 ++++++ src/entity.cpp | 2 +- src/llvm_backend.hpp | 7 ++++++ src/llvm_backend_proc.cpp | 27 +++++++++++++++++++++- src/parser.cpp | 1 + src/parser.hpp | 8 +++++-- 12 files changed, 136 insertions(+), 57 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 234f4afbd..e56211346 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -125,7 +125,7 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist // Returns: A formatted string. // @(require_results) -aprint :: proc(args: ..any, sep := " ", allocator := context.allocator) -> string { +aprint :: proc(#no_capture args: ..any, sep := " ", allocator := context.allocator) -> string { str: strings.Builder strings.builder_init(&str, allocator) return sbprint(&str, ..args, sep=sep) @@ -141,7 +141,7 @@ aprint :: proc(args: ..any, sep := " ", allocator := context.allocator) -> strin // Returns: A formatted string with a newline character at the end. // @(require_results) -aprintln :: proc(args: ..any, sep := " ", allocator := context.allocator) -> string { +aprintln :: proc(#no_capture args: ..any, sep := " ", allocator := context.allocator) -> string { str: strings.Builder strings.builder_init(&str, allocator) return sbprintln(&str, ..args, sep=sep) @@ -158,7 +158,7 @@ aprintln :: proc(args: ..any, sep := " ", allocator := context.allocator) -> str // Returns: A formatted string. The returned string must be freed accordingly. // @(require_results) -aprintf :: proc(fmt: string, args: ..any, allocator := context.allocator, newline := false) -> string { +aprintf :: proc(fmt: string, #no_capture args: ..any, allocator := context.allocator, newline := false) -> string { str: strings.Builder strings.builder_init(&str, allocator) return sbprintf(&str, fmt, ..args, newline=newline) @@ -174,7 +174,7 @@ aprintf :: proc(fmt: string, args: ..any, allocator := context.allocator, newlin // Returns: A formatted string. The returned string must be freed accordingly. // @(require_results) -aprintfln :: proc(fmt: string, args: ..any, allocator := context.allocator) -> string { +aprintfln :: proc(fmt: string, #no_capture args: ..any, allocator := context.allocator) -> string { return aprintf(fmt, ..args, allocator=allocator, newline=true) } // Creates a formatted string @@ -188,7 +188,7 @@ aprintfln :: proc(fmt: string, args: ..any, allocator := context.allocator) -> s // Returns: A formatted string. // @(require_results) -tprint :: proc(args: ..any, sep := " ") -> string { +tprint :: proc(#no_capture args: ..any, sep := " ") -> string { str: strings.Builder strings.builder_init(&str, context.temp_allocator) return sbprint(&str, ..args, sep=sep) @@ -204,7 +204,7 @@ tprint :: proc(args: ..any, sep := " ") -> string { // Returns: A formatted string with a newline character at the end. // @(require_results) -tprintln :: proc(args: ..any, sep := " ") -> string { +tprintln :: proc(#no_capture args: ..any, sep := " ") -> string { str: strings.Builder strings.builder_init(&str, context.temp_allocator) return sbprintln(&str, ..args, sep=sep) @@ -221,7 +221,7 @@ tprintln :: proc(args: ..any, sep := " ") -> string { // Returns: A formatted string. // @(require_results) -tprintf :: proc(fmt: string, args: ..any, newline := false) -> string { +tprintf :: proc(fmt: string, #no_capture args: ..any, newline := false) -> string { str: strings.Builder strings.builder_init(&str, context.temp_allocator) return sbprintf(&str, fmt, ..args, newline=newline) @@ -237,7 +237,7 @@ tprintf :: proc(fmt: string, args: ..any, newline := false) -> string { // Returns: A formatted string. // @(require_results) -tprintfln :: proc(fmt: string, args: ..any) -> string { +tprintfln :: proc(fmt: string, #no_capture args: ..any) -> string { return tprintf(fmt, ..args, newline=true) } // Creates a formatted string using a supplied buffer as the backing array. Writes into the buffer. @@ -249,7 +249,7 @@ tprintfln :: proc(fmt: string, args: ..any) -> string { // // Returns: A formatted string // -bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string { +bprint :: proc(buf: []byte, #no_capture args: ..any, sep := " ") -> string { sb := strings.builder_from_bytes(buf) return sbprint(&sb, ..args, sep=sep) } @@ -262,7 +262,7 @@ bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string { // // Returns: A formatted string with a newline character at the end // -bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string { +bprintln :: proc(buf: []byte, #no_capture args: ..any, sep := " ") -> string { sb := strings.builder_from_bytes(buf) return sbprintln(&sb, ..args, sep=sep) } @@ -276,7 +276,7 @@ bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string { // // Returns: A formatted string // -bprintf :: proc(buf: []byte, fmt: string, args: ..any, newline := false) -> string { +bprintf :: proc(buf: []byte, fmt: string, #no_capture args: ..any, newline := false) -> string { sb := strings.builder_from_bytes(buf) return sbprintf(&sb, fmt, ..args, newline=newline) } @@ -289,7 +289,7 @@ bprintf :: proc(buf: []byte, fmt: string, args: ..any, newline := false) -> stri // // Returns: A formatted string // -bprintfln :: proc(buf: []byte, fmt: string, args: ..any) -> string { +bprintfln :: proc(buf: []byte, fmt: string, #no_capture args: ..any) -> string { return bprintf(buf, fmt, ..args, newline=true) } // Runtime assertion with a formatted message @@ -301,14 +301,14 @@ bprintfln :: proc(buf: []byte, fmt: string, args: ..any) -> string { // - loc: The location of the caller // @(disabled=ODIN_DISABLE_ASSERT) -assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_location) { +assertf :: proc(condition: bool, fmt: string, #no_capture args: ..any, loc := #caller_location) { if !condition { // NOTE(dragos): We are using the same trick as in builtin.assert // to improve performance to make the CPU not // execute speculatively, making it about an order of // magnitude faster @(cold) - internal :: proc(loc: runtime.Source_Code_Location, fmt: string, args: ..any) { + internal :: proc(loc: runtime.Source_Code_Location, fmt: string, #no_capture args: ..any) { p := context.assertion_failure_proc if p == nil { p = runtime.default_assertion_failure_proc @@ -326,7 +326,7 @@ assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_locati // - args: A variadic list of arguments to be formatted // - loc: The location of the caller // -panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! { +panicf :: proc(fmt: string, #no_capture args: ..any, loc := #caller_location) -> ! { p := context.assertion_failure_proc if p == nil { p = runtime.default_assertion_failure_proc @@ -346,7 +346,7 @@ panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! { // Returns: A formatted C string // @(require_results) -caprintf :: proc(format: string, args: ..any, newline := false) -> cstring { +caprintf :: proc(format: string, #no_capture args: ..any, newline := false) -> cstring { str: strings.Builder strings.builder_init(&str) sbprintf(&str, format, ..args, newline=newline) @@ -365,7 +365,7 @@ caprintf :: proc(format: string, args: ..any, newline := false) -> cstring { // Returns: A formatted C string // @(require_results) -caprintfln :: proc(format: string, args: ..any) -> cstring { +caprintfln :: proc(format: string, #no_capture args: ..any) -> cstring { return caprintf(format, ..args, newline=true) } // Creates a formatted C string @@ -379,7 +379,7 @@ caprintfln :: proc(format: string, args: ..any) -> cstring { // Returns: A formatted C string. // @(require_results) -ctprint :: proc(args: ..any, sep := " ") -> cstring { +ctprint :: proc(#no_capture args: ..any, sep := " ") -> cstring { str: strings.Builder strings.builder_init(&str, context.temp_allocator) sbprint(&str, ..args, sep=sep) @@ -399,7 +399,7 @@ ctprint :: proc(args: ..any, sep := " ") -> cstring { // Returns: A formatted C string // @(require_results) -ctprintf :: proc(format: string, args: ..any, newline := false) -> cstring { +ctprintf :: proc(format: string, #no_capture args: ..any, newline := false) -> cstring { str: strings.Builder strings.builder_init(&str, context.temp_allocator) sbprintf(&str, format, ..args, newline=newline) @@ -418,7 +418,7 @@ ctprintf :: proc(format: string, args: ..any, newline := false) -> cstring { // Returns: A formatted C string // @(require_results) -ctprintfln :: proc(format: string, args: ..any) -> cstring { +ctprintfln :: proc(format: string, #no_capture args: ..any) -> cstring { return ctprintf(format, ..args, newline=true) } // Formats using the default print settings and writes to the given strings.Builder @@ -430,7 +430,7 @@ ctprintfln :: proc(format: string, args: ..any) -> cstring { // // Returns: A formatted string // -sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { +sbprint :: proc(buf: ^strings.Builder, #no_capture args: ..any, sep := " ") -> string { wprint(strings.to_writer(buf), ..args, sep=sep, flush=true) return strings.to_string(buf^) } @@ -443,7 +443,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { // // Returns: The resulting formatted string // -sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { +sbprintln :: proc(buf: ^strings.Builder, #no_capture args: ..any, sep := " ") -> string { wprintln(strings.to_writer(buf), ..args, sep=sep, flush=true) return strings.to_string(buf^) } @@ -457,7 +457,7 @@ sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { // // Returns: The resulting formatted string // -sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any, newline := false) -> string { +sbprintf :: proc(buf: ^strings.Builder, fmt: string, #no_capture args: ..any, newline := false) -> string { wprintf(strings.to_writer(buf), fmt, ..args, flush=true, newline=newline) return strings.to_string(buf^) } @@ -469,7 +469,7 @@ sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any, newline := fal // // Returns: A formatted string // -sbprintfln :: proc(buf: ^strings.Builder, format: string, args: ..any) -> string { +sbprintfln :: proc(buf: ^strings.Builder, format: string, #no_capture args: ..any) -> string { return sbprintf(buf, format, ..args, newline=true) } // Formats and writes to an io.Writer using the default print settings @@ -481,7 +481,7 @@ sbprintfln :: proc(buf: ^strings.Builder, format: string, args: ..any) -> string // // Returns: The number of bytes written // -wprint :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int { +wprint :: proc(w: io.Writer, #no_capture args: ..any, sep := " ", flush := true) -> int { fi: Info fi.writer = w @@ -522,7 +522,7 @@ wprint :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int { // // Returns: The number of bytes written // -wprintln :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int { +wprintln :: proc(w: io.Writer, #no_capture args: ..any, sep := " ", flush := true) -> int { fi: Info fi.writer = w @@ -549,11 +549,11 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int { // // Returns: The number of bytes written // -wprintf :: proc(w: io.Writer, fmt: string, args: ..any, flush := true, newline := false) -> int { +wprintf :: proc(w: io.Writer, fmt: string, #no_capture args: ..any, flush := true, newline := false) -> int { MAX_CHECKED_ARGS :: 64 assert(len(args) <= MAX_CHECKED_ARGS, "number of args > 64 is unsupported") - parse_options :: proc(fi: ^Info, fmt: string, index, end: int, unused_args: ^bit_set[0 ..< MAX_CHECKED_ARGS], args: ..any) -> int { + parse_options :: proc(fi: ^Info, fmt: string, index, end: int, unused_args: ^bit_set[0 ..< MAX_CHECKED_ARGS], #no_capture args: ..any) -> int { i := index // Prefix @@ -809,7 +809,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any, flush := true, newline : // // Returns: The number of bytes written. // -wprintfln :: proc(w: io.Writer, format: string, args: ..any, flush := true) -> int { +wprintfln :: proc(w: io.Writer, format: string, #no_capture args: ..any, flush := true) -> int { return wprintf(w, format, ..args, flush=flush, newline=true) } // Writes a ^runtime.Type_Info value to an io.Writer diff --git a/core/fmt/fmt_js.odin b/core/fmt/fmt_js.odin index acf218eb5..4389b8d87 100644 --- a/core/fmt/fmt_js.odin +++ b/core/fmt/fmt_js.odin @@ -43,7 +43,7 @@ fd_to_writer :: proc(fd: os.Handle, loc := #caller_location) -> io.Writer { } // fprint formats using the default print settings and writes to fd -fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { +fprint :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -54,7 +54,7 @@ fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #ca } // fprintln formats using the default print settings and writes to fd -fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { +fprintln :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -66,7 +66,7 @@ fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := # } // fprintf formats according to the specified format string and writes to fd -fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline := false, loc := #caller_location) -> int { +fprintf :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true, newline := false, loc := #caller_location) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -78,24 +78,24 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline } // fprintfln formats according to the specified format string and writes to fd, followed by a newline. -fprintfln :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, loc := #caller_location) -> int { +fprintfln :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true, loc := #caller_location) -> int { return fprintf(fd, fmt, ..args, flush=flush, newline=true, loc=loc) } // print formats using the default print settings and writes to stdout -print :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stdout, args=args, sep=sep, flush=flush) } +print :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprint(w=stdout, args=args, sep=sep, flush=flush) } // println formats using the default print settings and writes to stdout -println :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stdout, args=args, sep=sep, flush=flush) } +println :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stdout, args=args, sep=sep, flush=flush) } // printf formats according to the specififed format string and writes to stdout -printf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush) } +printf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush) } // printfln formats according to the specified format string and writes to stdout, followed by a newline. -printfln :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } +printfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } // eprint formats using the default print settings and writes to stderr -eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stderr, args=args, sep=sep, flush=flush) } +eprint :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprint(w=stderr, args=args, sep=sep, flush=flush) } // eprintln formats using the default print settings and writes to stderr -eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stderr, args=args, sep=sep, flush=flush) } +eprintln :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stderr, args=args, sep=sep, flush=flush) } // eprintf formats according to the specififed format string and writes to stderr -eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stderr, fmt, ..args, flush=flush) } +eprintf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stderr, fmt, ..args, flush=flush) } // eprintfln formats according to the specified format string and writes to stderr, followed by a newline. -eprintfln :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } +eprintfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } diff --git a/core/fmt/fmt_os.odin b/core/fmt/fmt_os.odin index 9de0d43be..538f7a08b 100644 --- a/core/fmt/fmt_os.odin +++ b/core/fmt/fmt_os.odin @@ -9,7 +9,7 @@ import "core:io" import "core:bufio" // fprint formats using the default print settings and writes to fd -fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { +fprint :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -20,7 +20,7 @@ fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { } // fprintln formats using the default print settings and writes to fd -fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { +fprintln :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -31,7 +31,7 @@ fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { return wprintln(w, ..args, sep=sep, flush=flush) } // fprintf formats according to the specified format string and writes to fd -fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline := false) -> int { +fprintf :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true, newline := false) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -42,7 +42,7 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline return wprintf(w, fmt, ..args, flush=flush, newline=newline) } // fprintfln formats according to the specified format string and writes to fd, followed by a newline. -fprintfln :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true) -> int { +fprintfln :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(fd, fmt, ..args, flush=flush, newline=true) } fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info, flush := true) -> (n: int, err: io.Error) { @@ -67,19 +67,19 @@ fprint_typeid :: proc(fd: os.Handle, id: typeid, flush := true) -> (n: int, err: } // print formats using the default print settings and writes to os.stdout -print :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(os.stdout, ..args, sep=sep, flush=flush) } +print :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprint(os.stdout, ..args, sep=sep, flush=flush) } // println formats using the default print settings and writes to os.stdout -println :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stdout, ..args, sep=sep, flush=flush) } +println :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stdout, ..args, sep=sep, flush=flush) } // printf formats according to the specified format string and writes to os.stdout -printf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush) } +printf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush) } // printfln formats according to the specified format string and writes to os.stdout, followed by a newline. -printfln :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush, newline=true) } +printfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush, newline=true) } // eprint formats using the default print settings and writes to os.stderr -eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(os.stderr, ..args, sep=sep, flush=flush) } +eprint :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprint(os.stderr, ..args, sep=sep, flush=flush) } // eprintln formats using the default print settings and writes to os.stderr -eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stderr, ..args, sep=sep, flush=flush) } +eprintln :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stderr, ..args, sep=sep, flush=flush) } // eprintf formats according to the specified format string and writes to os.stderr -eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush) } +eprintf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush) } // eprintfln formats according to the specified format string and writes to os.stderr, followed by a newline. -eprintfln :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush, newline=true) } +eprintfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush, newline=true) } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 12acca0cb..645d8ac5a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6033,6 +6033,23 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A Entity *vt = pt->params->Tuple.variables[pt->variadic_index]; o.type = vt->type; + + // NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameter that use `#no_capture` + // on the variadic parameter + if (c->decl && (vt->flags & EntityFlag_NoCapture)) { + bool found = false; + for (NoCaptureData &nc : c->decl->no_captures) { + if (are_types_identical(vt->type, nc.slice_type)) { + nc.max_count = gb_max(nc.max_count, variadic_operands.count); + found = true; + break; + } + } + if (!found) { + array_add(&c->decl->no_captures, NoCaptureData{vt->type, variadic_operands.count}); + } + } + } else { dummy_argument_count += 1; o.type = t_untyped_nil; diff --git a/src/check_type.cpp b/src/check_type.cpp index dd8559114..d1c9bb381 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1953,6 +1953,10 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para error(name, "'#by_ptr' can only be applied to variable fields"); p->flags &= ~FieldFlag_by_ptr; } + if (p->flags&FieldFlag_no_capture) { + error(name, "'#no_capture' can only be applied to variable variadic fields"); + p->flags &= ~FieldFlag_no_capture; + } param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved); param->TypeName.is_type_alias = true; @@ -2054,6 +2058,15 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para p->flags &= ~FieldFlag_by_ptr; // Remove the flag } } + if (p->flags&FieldFlag_no_capture) { + if (!(is_variadic && variadic_index == variables.count)) { + error(name, "'#no_capture' can only be applied to a variadic parameter"); + p->flags &= ~FieldFlag_no_capture; + } else if (p->flags & FieldFlag_c_vararg) { + error(name, "'#no_capture' cannot be applied to a #c_vararg parameter"); + p->flags &= ~FieldFlag_no_capture; + } + } if (is_poly_name) { if (p->flags&FieldFlag_no_alias) { @@ -2115,6 +2128,10 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (p->flags&FieldFlag_by_ptr) { param->flags |= EntityFlag_ByPtr; } + if (p->flags&FieldFlag_no_capture) { + param->flags |= EntityFlag_NoCapture; + } + param->state = EntityState_Resolved; // NOTE(bill): This should have be resolved whilst determining it add_entity(ctx, scope, name, param); diff --git a/src/checker.cpp b/src/checker.cpp index 8756cce1a..abacc13cb 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -184,6 +184,7 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { ptr_set_init(&d->deps, 0); ptr_set_init(&d->type_info_deps, 0); d->labels.allocator = heap_allocator(); + d->no_captures.allocator = heap_allocator(); } gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { diff --git a/src/checker.hpp b/src/checker.hpp index 781737140..17722f6b6 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -181,6 +181,11 @@ char const *ProcCheckedState_strings[ProcCheckedState_COUNT] { "Checked", }; +struct NoCaptureData { + Type *slice_type; // ..elem_type + isize max_count; +}; + // DeclInfo is used to store information of certain declarations to allow for "any order" usage struct DeclInfo { DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment @@ -219,6 +224,8 @@ struct DeclInfo { Array labels; + Array no_captures; + // NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time struct lbModule *code_gen_module; }; diff --git a/src/entity.cpp b/src/entity.cpp index 41d84e0f7..db6ffdd52 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -45,7 +45,7 @@ enum EntityFlag : u64 { EntityFlag_Value = 1ull<<11, EntityFlag_BitFieldField = 1ull<<12, - + EntityFlag_NoCapture = 1ull<<13, // #no_capture EntityFlag_PolyConst = 1ull<<15, EntityFlag_NotExported = 1ull<<16, diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 005358734..dd1041702 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -296,6 +296,11 @@ enum lbProcedureFlag : u32 { lbProcedureFlag_DebugAllocaCopy = 1<<1, }; +struct lbNoCaptureData { + Type *slice_type; + lbAddr base_array; +}; + struct lbProcedure { u32 flags; u16 state_flags; @@ -336,6 +341,8 @@ struct lbProcedure { bool in_multi_assignment; Array raw_input_parameters; + Array no_captures; + LLVMValueRef temp_callee_return_struct_memory; Ast *curr_stmt; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 610c34de2..ec244e185 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -517,6 +517,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { lb_start_block(p, p->entry_block); map_init(&p->direct_parameters); + p->no_captures.allocator = heap_allocator(); GB_ASSERT(p->type != nullptr); @@ -3450,8 +3451,32 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } isize slice_len = var_args.count; if (slice_len > 0) { + lbAddr base_array = {}; + if (e->flags & EntityFlag_NoCapture) { + for (lbNoCaptureData const &nc : p->no_captures) { + if (are_types_identical(nc.slice_type, slice_type)) { + base_array = nc.base_array; + break; + } + } + DeclInfo *d = decl_info_of_entity(p->entity); + if (d != nullptr && base_array.addr.value == nullptr) { + for (NoCaptureData const &nc : d->no_captures) { + if (are_types_identical(nc.slice_type, slice_type)) { + base_array = lb_add_local_generated(p, alloc_type_array(elem_type, nc.max_count), true); + array_add(&p->no_captures, lbNoCaptureData{slice_type, base_array}); + break; + } + } + } + } + + if (base_array.addr.value == nullptr) { + base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true); + } + GB_ASSERT(base_array.addr.value != nullptr); + lbAddr slice = lb_add_local_generated(p, slice_type, true); - lbAddr base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true); for (isize i = 0; i < var_args.count; i++) { lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)i); diff --git a/src/parser.cpp b/src/parser.cpp index 9ce3d563d..a6a146cfd 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4014,6 +4014,7 @@ struct ParseFieldPrefixMapping { gb_global ParseFieldPrefixMapping const parse_field_prefix_mappings[] = { {str_lit("using"), Token_using, FieldFlag_using}, {str_lit("no_alias"), Token_Hash, FieldFlag_no_alias}, + {str_lit("no_capture"), Token_Hash, FieldFlag_no_capture}, {str_lit("c_vararg"), Token_Hash, FieldFlag_c_vararg}, {str_lit("const"), Token_Hash, FieldFlag_const}, {str_lit("any_int"), Token_Hash, FieldFlag_any_int}, diff --git a/src/parser.hpp b/src/parser.hpp index 86b3393af..15176f789 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -330,9 +330,10 @@ enum FieldFlag : u32 { FieldFlag_subtype = 1<<7, FieldFlag_by_ptr = 1<<8, FieldFlag_no_broadcast = 1<<9, // disallow array programming + FieldFlag_no_capture = 1<<10, // Internal use by the parser only - FieldFlag_Tags = 1<<10, + FieldFlag_Tags = 1<<11, FieldFlag_Results = 1<<16, @@ -340,7 +341,10 @@ enum FieldFlag : u32 { FieldFlag_Invalid = 1u<<31, // Parameter List Restrictions - FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr|FieldFlag_no_broadcast, + FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg| + FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr|FieldFlag_no_broadcast| + FieldFlag_no_capture, + FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags, }; -- cgit v1.2.3 From 3dff83f3dc2914cdfb9a8f19cf990682cda41b03 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Jul 2024 12:39:30 +0100 Subject: Mock out `#no_capture` for future use --- src/check_expr.cpp | 13 ++++++------- src/check_type.cpp | 32 ++++++++++++++++++++++++-------- src/checker.cpp | 2 +- src/checker.hpp | 4 ++-- src/llvm_abi.cpp | 6 ++++++ src/llvm_backend.hpp | 4 ++-- src/llvm_backend_proc.cpp | 32 +++++++++++++------------------- 7 files changed, 54 insertions(+), 39 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 645d8ac5a..4edd34990 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6034,19 +6034,18 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A Entity *vt = pt->params->Tuple.variables[pt->variadic_index]; o.type = vt->type; - // NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameter that use `#no_capture` - // on the variadic parameter - if (c->decl && (vt->flags & EntityFlag_NoCapture)) { + // NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameters with the backing array + if (c->decl) { bool found = false; - for (NoCaptureData &nc : c->decl->no_captures) { - if (are_types_identical(vt->type, nc.slice_type)) { - nc.max_count = gb_max(nc.max_count, variadic_operands.count); + for (auto &vr : c->decl->variadic_reuses) { + if (are_types_identical(vt->type, vr.slice_type)) { + vr.max_count = gb_max(vr.max_count, variadic_operands.count); found = true; break; } } if (!found) { - array_add(&c->decl->no_captures, NoCaptureData{vt->type, variadic_operands.count}); + array_add(&c->decl->variadic_reuses, VariadicReuseData{vt->type, variadic_operands.count}); } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 466b9b3cd..7b75bf503 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1954,7 +1954,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para p->flags &= ~FieldFlag_by_ptr; } if (p->flags&FieldFlag_no_capture) { - error(name, "'#no_capture' can only be applied to variable variadic fields"); + error(name, "'#no_capture' can only be applied to variable fields"); p->flags &= ~FieldFlag_no_capture; } @@ -2059,16 +2059,32 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para } } if (p->flags&FieldFlag_no_capture) { - if (!(is_variadic && variadic_index == variables.count)) { - error(name, "'#no_capture' can only be applied to a variadic parameter"); - p->flags &= ~FieldFlag_no_capture; - } else if (p->flags & FieldFlag_c_vararg) { - error(name, "'#no_capture' cannot be applied to a #c_vararg parameter"); - p->flags &= ~FieldFlag_no_capture; + if (is_variadic && variadic_index == variables.count) { + if (p->flags & FieldFlag_c_vararg) { + error(name, "'#no_capture' cannot be applied to a #c_vararg parameter"); + p->flags &= ~FieldFlag_no_capture; + } else { + error(name, "'#no_capture' is already implied on all variadic parameter"); + } + } else if (is_type_polymorphic(type)) { + // ignore } else { - error(name, "'#no_capture' is already implied on all variadic parameter"); + if (is_type_internally_pointer_like(type)) { + // okay + } else if (is_type_slice(type) || is_type_string(type)) { + // okay + } else if (is_type_dynamic_array(type)) { + // okay + } else { + ERROR_BLOCK(); + error(name, "'#no_capture' can only be applied to pointer-like types, slices, strings, and dynamic arrays"); + error_line("\t'#no_capture' does not currently do anything useful\n"); + p->flags &= ~FieldFlag_no_capture; + } } } + + if (is_poly_name) { if (p->flags&FieldFlag_no_alias) { error(name, "'#no_alias' can only be applied to non constant values"); diff --git a/src/checker.cpp b/src/checker.cpp index abacc13cb..9adf4ef3c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -184,7 +184,7 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { ptr_set_init(&d->deps, 0); ptr_set_init(&d->type_info_deps, 0); d->labels.allocator = heap_allocator(); - d->no_captures.allocator = heap_allocator(); + d->variadic_reuses.allocator = heap_allocator(); } gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { diff --git a/src/checker.hpp b/src/checker.hpp index 17722f6b6..2fadbe56a 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -181,7 +181,7 @@ char const *ProcCheckedState_strings[ProcCheckedState_COUNT] { "Checked", }; -struct NoCaptureData { +struct VariadicReuseData { Type *slice_type; // ..elem_type isize max_count; }; @@ -224,7 +224,7 @@ struct DeclInfo { Array labels; - Array no_captures; + Array variadic_reuses; // NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time struct lbModule *code_gen_module; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index b2e485d01..9a3479b34 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -15,6 +15,7 @@ struct lbArgType { LLVMAttributeRef align_attribute; // Optional i64 byval_alignment; bool is_byval; + bool no_capture; }; @@ -159,6 +160,11 @@ gb_internal void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType LLVMAddAttributeAtIndex(fn, arg_index+1, arg->align_attribute); } + if (arg->no_capture) { + LLVMAddAttributeAtIndex(fn, arg_index+1, nocapture_attr); + } + + if (ft->multiple_return_original_type) { if (ft->original_arg_count <= i) { LLVMAddAttributeAtIndex(fn, arg_index+1, noalias_attr); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 71fa1dbd0..24494e2af 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -296,7 +296,7 @@ enum lbProcedureFlag : u32 { lbProcedureFlag_DebugAllocaCopy = 1<<1, }; -struct lbNoCaptureData { +struct lbVariadicReuseData { Type *slice_type; lbAddr base_array; }; @@ -341,7 +341,7 @@ struct lbProcedure { bool in_multi_assignment; Array raw_input_parameters; - Array no_captures; + Array variadic_reuses; LLVMValueRef temp_callee_return_struct_memory; Ast *curr_stmt; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ec244e185..1585df865 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -517,7 +517,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { lb_start_block(p, p->entry_block); map_init(&p->direct_parameters); - p->no_captures.allocator = heap_allocator(); + p->variadic_reuses.allocator = heap_allocator(); GB_ASSERT(p->type != nullptr); @@ -3452,28 +3452,22 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { isize slice_len = var_args.count; if (slice_len > 0) { lbAddr base_array = {}; - if (e->flags & EntityFlag_NoCapture) { - for (lbNoCaptureData const &nc : p->no_captures) { - if (are_types_identical(nc.slice_type, slice_type)) { - base_array = nc.base_array; - break; - } + for (auto const &vr : p->variadic_reuses) { + if (are_types_identical(vr.slice_type, slice_type)) { + base_array = vr.base_array; + break; } - DeclInfo *d = decl_info_of_entity(p->entity); - if (d != nullptr && base_array.addr.value == nullptr) { - for (NoCaptureData const &nc : d->no_captures) { - if (are_types_identical(nc.slice_type, slice_type)) { - base_array = lb_add_local_generated(p, alloc_type_array(elem_type, nc.max_count), true); - array_add(&p->no_captures, lbNoCaptureData{slice_type, base_array}); - break; - } + } + DeclInfo *d = decl_info_of_entity(p->entity); + if (d != nullptr && base_array.addr.value == nullptr) { + for (auto const &vr : d->variadic_reuses) { + if (are_types_identical(vr.slice_type, slice_type)) { + base_array = lb_add_local_generated(p, alloc_type_array(elem_type, vr.max_count), true); + array_add(&p->variadic_reuses, lbVariadicReuseData{slice_type, base_array}); + break; } } } - - if (base_array.addr.value == nullptr) { - base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true); - } GB_ASSERT(base_array.addr.value != nullptr); lbAddr slice = lb_add_local_generated(p, slice_type, true); -- cgit v1.2.3 From 556355ef054bc5139a24f8b5dbd210049e908c95 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Jul 2024 15:30:40 +0100 Subject: Disallow global use of target specific procedure calls --- src/check_expr.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4edd34990..3b1f86114 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7904,12 +7904,15 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c // 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)); + if (c->curr_proc_decl == nullptr) { + error(call, "Inlined procedure which enables target feature '%.*s' cannot be used at the global/file scope", LIT(invalid)); + } else { + 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)); + } } } } -- cgit v1.2.3 From 11e2aa2d519a9522bc6a71abf4868216ed236c89 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Jul 2024 15:31:40 +0100 Subject: Improve error message --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3b1f86114..82f64738f 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7905,7 +7905,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c // NOTE: Due to restrictions in LLVM you can not inline calls with a superset of features. if (is_call_inlined) { if (c->curr_proc_decl == nullptr) { - error(call, "Inlined procedure which enables target feature '%.*s' cannot be used at the global/file scope", LIT(invalid)); + error(call, "Calling a '#force_inline' procedure that enables target features is not allowed at file scope"); } else { GB_ASSERT(c->curr_proc_decl->entity); GB_ASSERT(c->curr_proc_decl->entity->type->kind == Type_Proc); -- cgit v1.2.3 From eb6805ef401f03ccfe0c2f8a71097e2560f804a8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 15 Jul 2024 01:44:23 +0100 Subject: Disable the need for mutexes in single threaded checker stage --- src/check_expr.cpp | 4 +++- src/checker.cpp | 49 +++++++++++++++++++------------------------------ src/types.cpp | 20 ++++++++++---------- 3 files changed, 32 insertions(+), 41 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 82f64738f..3fcfe29f5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -500,7 +500,9 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E nctx.no_polymorphic_errors = false; // NOTE(bill): Reset scope from the failed procedure type - scope_reset(scope); + scope->head_child.store(nullptr, std::memory_order_relaxed); + string_map_clear(&scope->elements); + ptr_set_clear(&scope->imported); // LEAK NOTE(bill): Cloning this AST may be leaky but this is not really an issue due to arena-based allocation Ast *cloned_proc_type_node = clone_ast(pt->node); diff --git a/src/checker.cpp b/src/checker.cpp index cc39e9a44..290c0b2b0 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1,5 +1,7 @@ #define DEBUG_CHECK_ALL_PROCEDURES 1 +gb_global bool in_single_threaded_checker_stage = false; + #include "entity.cpp" #include "types.cpp" @@ -50,15 +52,6 @@ gb_internal bool check_rtti_type_disallowed(Ast *expr, Type *type, char const *f return check_rtti_type_disallowed(ast_token(expr), type, format); } -gb_internal void scope_reset(Scope *scope) { - if (scope == nullptr) return; - - rw_mutex_lock(&scope->mutex); - scope->head_child.store(nullptr, std::memory_order_relaxed); - string_map_clear(&scope->elements); - ptr_set_clear(&scope->imported); - rw_mutex_unlock(&scope->mutex); -} gb_internal void scope_reserve(Scope *scope, isize count) { string_map_reserve(&scope->elements, 2*count); @@ -168,16 +161,13 @@ gb_internal void import_graph_node_swap(ImportGraphNode **data, isize i, isize j } - - - gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { gb_zero_item(d); if (parent) { - mutex_lock(&parent->next_mutex); + if (!in_single_threaded_checker_stage) mutex_lock(&parent->next_mutex); d->next_sibling = parent->next_child; parent->next_child = d; - mutex_unlock(&parent->next_mutex); + if (!in_single_threaded_checker_stage) mutex_unlock(&parent->next_mutex); } d->parent = parent; d->scope = scope; @@ -384,7 +374,6 @@ gb_internal Entity *scope_lookup_current(Scope *s, String const &name) { return nullptr; } -gb_global bool in_single_threaded_mode_scopes = false; gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_) { if (scope != nullptr) { @@ -393,9 +382,9 @@ gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **s StringHashKey key = string_hash_string(name); for (Scope *s = scope; s != nullptr; s = s->parent) { Entity **found = nullptr; - if (!in_single_threaded_mode_scopes) rw_mutex_shared_lock(&s->mutex); + if (!in_single_threaded_checker_stage) rw_mutex_shared_lock(&s->mutex); found = string_map_get(&s->elements, key); - if (!in_single_threaded_mode_scopes) rw_mutex_shared_unlock(&s->mutex); + if (!in_single_threaded_checker_stage) rw_mutex_shared_unlock(&s->mutex); if (found) { Entity *e = *found; if (gone_thru_proc) { @@ -515,7 +504,7 @@ end:; gb_internal Entity *scope_insert(Scope *s, Entity *entity) { String name = entity->token.string; - if (in_single_threaded_mode_scopes) { + if (in_single_threaded_checker_stage) { return scope_insert_with_name_no_mutex(s, name, entity); } else { return scope_insert_with_name(s, name, entity); @@ -773,17 +762,17 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { gb_internal void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) { - rw_mutex_lock(&d->deps_mutex); + if (!in_single_threaded_checker_stage) rw_mutex_lock(&d->deps_mutex); ptr_set_add(&d->deps, e); - rw_mutex_unlock(&d->deps_mutex); + if (!in_single_threaded_checker_stage) rw_mutex_unlock(&d->deps_mutex); } gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type) { if (d == nullptr) { return; } - rw_mutex_lock(&d->type_info_deps_mutex); + if (!in_single_threaded_checker_stage) rw_mutex_lock(&d->type_info_deps_mutex); ptr_set_add(&d->type_info_deps, type); - rw_mutex_unlock(&d->type_info_deps_mutex); + if (!in_single_threaded_checker_stage) rw_mutex_unlock(&d->type_info_deps_mutex); } @@ -1394,7 +1383,7 @@ gb_internal void reset_checker_context(CheckerContext *ctx, AstFile *file, Untyp return; } GB_ASSERT(ctx->checker != nullptr); - mutex_lock(&ctx->mutex); + if (!in_single_threaded_checker_stage) mutex_lock(&ctx->mutex); auto type_path = ctx->type_path; array_clear(type_path); @@ -1413,7 +1402,7 @@ gb_internal void reset_checker_context(CheckerContext *ctx, AstFile *file, Untyp ctx->untyped = untyped; - mutex_unlock(&ctx->mutex); + if (!in_single_threaded_checker_stage) mutex_unlock(&ctx->mutex); } @@ -1559,9 +1548,9 @@ gb_internal void check_set_expr_info(CheckerContext *c, Ast *expr, AddressingMod if (c->untyped != nullptr) { map_set(c->untyped, expr, make_expr_info(mode, type, value, false)); } else { - rw_mutex_lock(&c->info->global_untyped_mutex); + if (!in_single_threaded_checker_stage) rw_mutex_lock(&c->info->global_untyped_mutex); map_set(&c->info->global_untyped, expr, make_expr_info(mode, type, value, false)); - rw_mutex_unlock(&c->info->global_untyped_mutex); + if (!in_single_threaded_checker_stage) rw_mutex_unlock(&c->info->global_untyped_mutex); } } @@ -1571,10 +1560,10 @@ gb_internal void check_remove_expr_info(CheckerContext *c, Ast *e) { GB_ASSERT(map_get(c->untyped, e) == nullptr); } else { auto *untyped = &c->info->global_untyped; - rw_mutex_lock(&c->info->global_untyped_mutex); + if (!in_single_threaded_checker_stage) rw_mutex_lock(&c->info->global_untyped_mutex); map_remove(untyped, e); GB_ASSERT(map_get(untyped, e) == nullptr); - rw_mutex_unlock(&c->info->global_untyped_mutex); + if (!in_single_threaded_checker_stage) rw_mutex_unlock(&c->info->global_untyped_mutex); } } @@ -4596,7 +4585,7 @@ gb_internal void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d) } gb_internal void check_all_global_entities(Checker *c) { - in_single_threaded_mode_scopes = true; + in_single_threaded_checker_stage = true; // NOTE(bill): This must be single threaded // Don't bother trying @@ -4618,7 +4607,7 @@ gb_internal void check_all_global_entities(Checker *c) { } } - in_single_threaded_mode_scopes = false; + in_single_threaded_checker_stage = false; } diff --git a/src/types.cpp b/src/types.cpp index fdc174d81..d477f5dee 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -808,9 +808,9 @@ gb_internal void type_path_init(TypePath *tp) { } gb_internal void type_path_free(TypePath *tp) { - mutex_lock(&tp->mutex); + if (!in_single_threaded_checker_stage) mutex_lock(&tp->mutex); array_free(&tp->path); - mutex_unlock(&tp->mutex); + if (!in_single_threaded_checker_stage) mutex_unlock(&tp->mutex); } gb_internal void type_path_print_illegal_cycle(TypePath *tp, isize start_index) { @@ -839,7 +839,7 @@ gb_internal bool type_path_push(TypePath *tp, Type *t) { } Entity *e = t->Named.type_name; - mutex_lock(&tp->mutex); + if (!in_single_threaded_checker_stage) mutex_lock(&tp->mutex); for (isize i = 0; i < tp->path.count; i++) { Entity *p = tp->path[i]; @@ -850,18 +850,18 @@ gb_internal bool type_path_push(TypePath *tp, Type *t) { array_add(&tp->path, e); - mutex_unlock(&tp->mutex); + if (!in_single_threaded_checker_stage) mutex_unlock(&tp->mutex); return true; } gb_internal void type_path_pop(TypePath *tp) { if (tp != nullptr) { - mutex_lock(&tp->mutex); + if (!in_single_threaded_checker_stage) mutex_lock(&tp->mutex); if (tp->path.count > 0) { array_pop(&tp->path); } - mutex_unlock(&tp->mutex); + if (!in_single_threaded_checker_stage) mutex_unlock(&tp->mutex); } } @@ -3216,8 +3216,8 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name GB_ASSERT(e->kind == Entity_TypeName); if (e->TypeName.objc_metadata) { auto *md = e->TypeName.objc_metadata; - mutex_lock(md->mutex); - defer (mutex_unlock(md->mutex)); + if (!in_single_threaded_checker_stage) mutex_lock(md->mutex); + defer (if (!in_single_threaded_checker_stage) mutex_unlock(md->mutex)); for (TypeNameObjCMetadataEntry const &entry : md->type_entries) { GB_ASSERT(entry.entity->kind == Entity_Procedure || entry.entity->kind == Entity_ProcGroup); if (entry.name == field_name) { @@ -3294,8 +3294,8 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name GB_ASSERT(e->kind == Entity_TypeName); if (e->TypeName.objc_metadata) { auto *md = e->TypeName.objc_metadata; - mutex_lock(md->mutex); - defer (mutex_unlock(md->mutex)); + if (!in_single_threaded_checker_stage) mutex_lock(md->mutex); + defer (if (!in_single_threaded_checker_stage) mutex_unlock(md->mutex)); for (TypeNameObjCMetadataEntry const &entry : md->value_entries) { GB_ASSERT(entry.entity->kind == Entity_Procedure || entry.entity->kind == Entity_ProcGroup); if (entry.name == field_name) { -- cgit v1.2.3 From 1e37eaf54daf885636ea3ad9606a2b54e01721f9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 15 Jul 2024 14:49:20 +0100 Subject: Begin work for `bit_set[...; [N]T]` (not working) --- src/build_settings.cpp | 2 + src/check_expr.cpp | 6 ++- src/check_type.cpp | 21 ++------ src/llvm_backend_const.cpp | 2 + src/llvm_backend_expr.cpp | 120 ++++++++++++++++++++++++++++++++++--------- src/llvm_backend_general.cpp | 2 + src/llvm_backend_proc.cpp | 5 ++ src/main.cpp | 5 ++ src/types.cpp | 21 ++++++++ 9 files changed, 141 insertions(+), 43 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index e0e7810e6..49bb83b22 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -440,6 +440,8 @@ struct BuildContext { bool cached; BuildCacheData build_cache_data; + bool internal_no_inline; + bool no_threaded_checker; bool show_debug_messages; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3fcfe29f5..01ff9da5b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9947,10 +9947,14 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } Type *et = base_type(t->BitSet.elem); isize field_count = 0; - if (et->kind == Type_Enum) { + if (et != nullptr && et->kind == Type_Enum) { field_count = et->Enum.fields.count; } + if (is_type_array(bit_set_to_int(t))) { + is_constant = false; + } + if (cl->elems[0]->kind == Ast_FieldValue) { error(cl->elems[0], "'field = value' in a bit_set a literal is not allowed"); is_constant = false; diff --git a/src/check_type.cpp b/src/check_type.cpp index fea937e4e..e3609970a 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -939,22 +939,6 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam enum_type->Enum.max_value_index = max_value_index; } -gb_internal bool is_valid_bit_field_backing_type(Type *type) { - if (type == nullptr) { - return false; - } - type = base_type(type); - if (is_type_untyped(type)) { - return false; - } - if (is_type_integer(type)) { - return true; - } - if (type->kind == Type_Array) { - return is_type_integer(type->Array.elem); - } - return false; -} gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, Type *named_type, Ast *node) { ast_node(bf, BitFieldType, node); @@ -1268,11 +1252,14 @@ gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_t Type *t = default_type(lhs.type); if (bs->underlying != nullptr) { Type *u = check_type(c, bs->underlying); + // if (!is_valid_bit_field_backing_type(u)) { if (!is_type_integer(u)) { gbString ts = type_to_string(u); error(bs->underlying, "Expected an underlying integer for the bit set, got %s", ts); gb_string_free(ts); - return; + if (!is_valid_bit_field_backing_type(u)) { + return; + } } type->BitSet.underlying = u; } diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 5d9caeba1..12bcc4e1f 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -434,6 +434,8 @@ gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, Bi } } + GB_ASSERT(!is_type_array(original_type)); + LLVMValueRef value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), cast(unsigned)((sz+7)/8), cast(u64 *)rop); if (big_int_is_neg(a)) { value = LLVMConstNeg(value); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index bcacc0537..dfb7e162e 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -296,12 +296,6 @@ gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValu GB_ASSERT(vector_type0 == vector_type1); LLVMTypeRef vector_type = vector_type0; - LLVMValueRef lhs_vp = LLVMBuildPointerCast(p->builder, lhs_ptr.value, LLVMPointerType(vector_type, 0), ""); - LLVMValueRef rhs_vp = LLVMBuildPointerCast(p->builder, rhs_ptr.value, LLVMPointerType(vector_type, 0), ""); - LLVMValueRef x = LLVMBuildLoad2(p->builder, vector_type, lhs_vp, ""); - LLVMValueRef y = LLVMBuildLoad2(p->builder, vector_type, rhs_vp, ""); - LLVMValueRef z = nullptr; - Type *integral_type = base_type(elem_type); if (is_type_simd_vector(integral_type)) { integral_type = core_array_type(integral_type); @@ -311,8 +305,18 @@ gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValu case Token_Add: op = Token_Or; break; case Token_Sub: op = Token_AndNot; break; } + Type *u = bit_set_to_int(type); + if (is_type_array(u)) { + return false; + } } + LLVMValueRef lhs_vp = LLVMBuildPointerCast(p->builder, lhs_ptr.value, LLVMPointerType(vector_type, 0), ""); + LLVMValueRef rhs_vp = LLVMBuildPointerCast(p->builder, rhs_ptr.value, LLVMPointerType(vector_type, 0), ""); + LLVMValueRef x = LLVMBuildLoad2(p->builder, vector_type, lhs_vp, ""); + LLVMValueRef y = LLVMBuildLoad2(p->builder, vector_type, rhs_vp, ""); + LLVMValueRef z = nullptr; + if (is_type_float(integral_type)) { switch (op) { case Token_Add: @@ -1286,6 +1290,14 @@ handle_op:; case Token_Add: op = Token_Or; break; case Token_Sub: op = Token_AndNot; break; } + Type *u = bit_set_to_int(type); + if (is_type_array(u)) { + lhs.type = u; + rhs.type = u; + res = lb_emit_arith(p, op, lhs, rhs, u); + res.type = type; + return res; + } } Type *integral_type = type; @@ -1441,6 +1453,7 @@ gb_internal lbValue lb_build_binary_in(lbProcedure *p, lbValue left, lbValue rig GB_ASSERT(are_types_identical(left.type, key_type)); Type *it = bit_set_to_int(rt); + left = lb_emit_conv(p, left, it); if (is_type_different_to_arch_endianness(it)) { left = lb_emit_byte_swap(p, left, integer_endian_type_to_platform_type(it)); @@ -2054,6 +2067,26 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } } + // bit_set <-> backing type + if (is_type_bit_set(src)) { + Type *backing = bit_set_to_int(src); + if (are_types_identical(backing, dst)) { + lbValue res = {}; + res.type = t; + res.value = value.value; + return res; + } + } + if (is_type_bit_set(dst)) { + Type *backing = bit_set_to_int(dst); + if (are_types_identical(src, backing)) { + lbValue res = {}; + res.type = t; + res.value = value.value; + return res; + } + } + // Pointer <-> uintptr if (is_type_pointer(src) && is_type_uintptr(dst)) { @@ -2951,13 +2984,32 @@ gb_internal lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, case Type_Pointer: case Type_MultiPointer: case Type_Proc: - case Type_BitSet: if (op_kind == Token_CmpEq) { res.value = LLVMBuildIsNull(p->builder, x.value, ""); } else if (op_kind == Token_NotEq) { res.value = LLVMBuildIsNotNull(p->builder, x.value, ""); } return res; + case Type_BitSet: + { + Type *u = bit_set_to_int(bt); + if (is_type_array(u)) { + auto args = array_make(permanent_allocator(), 2); + lbValue lhs = lb_address_from_load_or_generate_local(p, x); + args[0] = lb_emit_conv(p, lhs, t_rawptr); + args[1] = lb_const_int(p->module, t_int, type_size_of(t)); + lbValue val = lb_emit_runtime_call(p, "memory_compare_zero", args); + lbValue res = lb_emit_comp(p, op_kind, val, lb_const_int(p->module, t_int, 0)); + return res; + } else { + if (op_kind == Token_CmpEq) { + res.value = LLVMBuildIsNull(p->builder, x.value, ""); + } else if (op_kind == Token_NotEq) { + res.value = LLVMBuildIsNotNull(p->builder, x.value, ""); + } + } + return res; + } case Type_Slice: { @@ -4878,29 +4930,47 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { case Type_BitSet: { i64 sz = type_size_of(type); if (cl->elems.count > 0 && sz > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower)); - for (Ast *elem : cl->elems) { - GB_ASSERT(elem->kind != Ast_FieldValue); - if (lb_is_elem_const(elem, et)) { - continue; + Type *backing = bit_set_to_int(type); + if (is_type_array(backing)) { + GB_PANIC("TODO: bit_set [N]T"); + Type *base_it = core_array_type(backing); + i64 bits_per_elem = 8*type_size_of(base_it); + gb_unused(bits_per_elem); + lbValue one = lb_const_value(p->module, t_i64, exact_value_i64(1)); + for (Ast *elem : cl->elems) { + GB_ASSERT(elem->kind != Ast_FieldValue); + lbValue expr = lb_build_expr(p, elem); + GB_ASSERT(expr.type->kind != Type_Tuple); + + lbValue e = lb_emit_conv(p, expr, t_i64); + e = lb_emit_arith(p, Token_Sub, e, lower, t_i64); + // lbValue idx = lb_emit_arith(p, Token_Div, e, bits_per_elem, t_i64); + // lbValue val = lb_emit_arith(p, Token_Div, e, bits_per_elem, t_i64); } - - lbValue expr = lb_build_expr(p, elem); - GB_ASSERT(expr.type->kind != Type_Tuple); - + } else { Type *it = bit_set_to_int(bt); lbValue one = lb_const_value(p->module, it, exact_value_i64(1)); - lbValue e = lb_emit_conv(p, expr, it); - e = lb_emit_arith(p, Token_Sub, e, lower, it); - e = lb_emit_arith(p, Token_Shl, one, e, it); - - lbValue old_value = lb_emit_transmute(p, lb_addr_load(p, v), it); - lbValue new_value = lb_emit_arith(p, Token_Or, old_value, e, it); - new_value = lb_emit_transmute(p, new_value, type); - lb_addr_store(p, v, new_value); + for (Ast *elem : cl->elems) { + GB_ASSERT(elem->kind != Ast_FieldValue); + + if (lb_is_elem_const(elem, et)) { + continue; + } + + lbValue expr = lb_build_expr(p, elem); + GB_ASSERT(expr.type->kind != Type_Tuple); + + lbValue e = lb_emit_conv(p, expr, it); + e = lb_emit_arith(p, Token_Sub, e, lower, it); + e = lb_emit_arith(p, Token_Shl, one, e, it); + + lbValue old_value = lb_emit_transmute(p, lb_addr_load(p, v), it); + lbValue new_value = lb_emit_arith(p, Token_Or, old_value, e, it); + new_value = lb_emit_transmute(p, new_value, type); + lb_addr_store(p, v, new_value); + } } } break; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index bb04fc746..a91c1d1fe 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1023,6 +1023,8 @@ gb_internal void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr); LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0); LLVMBuildStore(p->builder, LLVMConstNull(rawptr_type), LLVMBuildBitCast(p->builder, ptr.value, rawptr_ptr_type, "")); + } else if (is_type_bit_set(a)) { + lb_mem_zero_ptr(p, ptr.value, a, 1); } else if (lb_sizeof(src_t) <= lb_max_zero_init_size()) { LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value); } else { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index eefe1c422..4ee4fb769 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -159,6 +159,11 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i case ProcInlining_no_inline: lb_add_attribute_to_proc(m, p->value, "noinline"); break; + default: + if (build_context.internal_no_inline) { + lb_add_attribute_to_proc(m, p->value, "noinline"); + break; + } } switch (entity->Procedure.optimization_mode) { diff --git a/src/main.cpp b/src/main.cpp index 0c3ef1399..e7f4ccc0a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -394,6 +394,7 @@ enum BuildFlagKind { BuildFlag_InternalIgnorePanic, BuildFlag_InternalModulePerFile, BuildFlag_InternalCached, + BuildFlag_InternalNoInline, BuildFlag_Tilde, @@ -598,6 +599,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_InternalIgnorePanic, str_lit("internal-ignore-panic"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalModulePerFile, str_lit("internal-module-per-file"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalCached, str_lit("internal-cached"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalNoInline, str_lit("internal-no-inline"), BuildFlagParam_None, Command_all); #if ALLOW_TILDE add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); @@ -1422,6 +1424,9 @@ gb_internal bool parse_build_flags(Array args) { build_context.cached = true; build_context.use_separate_modules = true; break; + case BuildFlag_InternalNoInline: + build_context.internal_no_inline = true; + break; case BuildFlag_Tilde: build_context.tilde_backend = true; diff --git a/src/types.cpp b/src/types.cpp index fdc174d81..3f86d4c50 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2011,6 +2011,24 @@ gb_internal bool is_type_valid_bit_set_elem(Type *t) { return false; } + +gb_internal bool is_valid_bit_field_backing_type(Type *type) { + if (type == nullptr) { + return false; + } + type = base_type(type); + if (is_type_untyped(type)) { + return false; + } + if (is_type_integer(type)) { + return true; + } + if (type->kind == Type_Array) { + return is_type_integer(type->Array.elem); + } + return false; +} + gb_internal Type *bit_set_to_int(Type *t) { GB_ASSERT(is_type_bit_set(t)); Type *bt = base_type(t); @@ -2018,6 +2036,9 @@ gb_internal Type *bit_set_to_int(Type *t) { if (underlying != nullptr && is_type_integer(underlying)) { return underlying; } + if (underlying != nullptr && is_valid_bit_field_backing_type(underlying)) { + return underlying; + } i64 sz = type_size_of(t); switch (sz) { -- cgit v1.2.3 From e60951a902976acfef74b863463bb116858366c5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 10:51:08 +0100 Subject: Begin converting `os.Errno` to be a `nil`-able type as a transition period --- core/crypto/rand_windows.odin | 2 +- core/os/os.odin | 6 + core/os/os2/errors.odin | 8 +- core/os/os2/errors_linux.odin | 2 +- core/os/os2/errors_windows.odin | 2 +- core/os/os2/file_stream.odin | 2 +- core/os/os2/process.odin | 2 +- core/os/os2/process_windows.odin | 14 +- core/os/os_darwin.odin | 393 +++++++++++++++++++++++++-------------- core/os/os_essence.odin | 36 ++-- core/os/os_freebsd.odin | 291 +++++++++++++++++++---------- core/os/os_haiku.odin | 14 +- core/os/os_js.odin | 92 ++++++--- core/os/os_linux.odin | 264 +++++++++++++------------- core/os/os_netbsd.odin | 349 +++++++++++++++++++++++----------- core/os/os_openbsd.odin | 299 +++++++++++++++++++---------- core/os/os_wasi.odin | 6 +- core/os/os_windows.odin | 61 +++--- core/prof/spall/spall_unix.odin | 4 +- core/sync/futex_haiku.odin | 11 +- core/sys/haiku/os.odin | 2 +- src/check_expr.cpp | 21 +++ 22 files changed, 1190 insertions(+), 691 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/core/crypto/rand_windows.odin b/core/crypto/rand_windows.odin index 9cd647cc1..6392cd51f 100644 --- a/core/crypto/rand_windows.odin +++ b/core/crypto/rand_windows.odin @@ -10,7 +10,7 @@ HAS_RAND_BYTES :: true _rand_bytes :: proc(dst: []byte) { ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)) if ret != os.ERROR_NONE { - switch ret { + #partial switch ret { case os.ERROR_INVALID_HANDLE: // The handle to the first parameter is invalid. // This should not happen here, since we explicitly pass nil to it diff --git a/core/os/os.odin b/core/os/os.odin index 51652a52b..3f48c59df 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -13,6 +13,12 @@ SEEK_SET :: 0 SEEK_CUR :: 1 SEEK_END :: 2 +Platform_Error :: _Platform_Error +Error :: Platform_Error +Errno :: Error // alias + +ERROR_NONE :: Errno(0) + write_string :: proc(fd: Handle, str: string) -> (int, Errno) { return write(fd, transmute([]byte)str) } diff --git a/core/os/os2/errors.odin b/core/os/os2/errors.odin index 2b9b3528e..e5a0bb722 100644 --- a/core/os/os2/errors.odin +++ b/core/os/os2/errors.odin @@ -3,7 +3,7 @@ package os2 import "core:io" import "base:runtime" -General_Error :: enum u32 { +General_Platform_Error :: enum u32 { None, Permission_Denied, @@ -29,7 +29,7 @@ General_Error :: enum u32 { Unsupported, } -Platform_Error :: enum i32 {None=0} +Platform_Platform_Error :: enum i32 {None=0} Error :: union #shared_nil { General_Error, @@ -43,7 +43,7 @@ ERROR_NONE :: Error{} -is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) { +is_platform_Platform_Error :: proc(ferr: Error) -> (err: i32, ok: bool) { v := ferr.(Platform_Error) or_else {} return i32(v), i32(v) != 0 } @@ -104,7 +104,7 @@ error_string :: proc(ferr: Error) -> string { return "unknown error" } -print_error :: proc(f: ^File, ferr: Error, msg: string) { +print_Platform_Error :: proc(f: ^File, ferr: Error, msg: string) { TEMP_ALLOCATOR_GUARD() err_str := error_string(ferr) diff --git a/core/os/os2/errors_linux.odin b/core/os/os2/errors_linux.odin index d7234ce8b..0da9e1452 100644 --- a/core/os/os2/errors_linux.odin +++ b/core/os/os2/errors_linux.odin @@ -142,7 +142,7 @@ _errno_strings : [linux.Errno]string = { } -_get_platform_error :: proc(errno: linux.Errno) -> Error { +_get_platform_Platform_Error :: proc(errno: linux.Errno) -> Error { #partial switch errno { case .NONE: return nil diff --git a/core/os/os2/errors_windows.odin b/core/os/os2/errors_windows.odin index 6421d26ee..00dacd491 100644 --- a/core/os/os2/errors_windows.odin +++ b/core/os/os2/errors_windows.odin @@ -20,7 +20,7 @@ _error_string :: proc(errno: i32) -> string { return "" } -_get_platform_error :: proc() -> Error { +_get_platform_Platform_Error :: proc() -> Error { err := win32.GetLastError() if err == 0 { return nil diff --git a/core/os/os2/file_stream.odin b/core/os/os2/file_stream.odin index 84176928d..89bd59809 100644 --- a/core/os/os2/file_stream.odin +++ b/core/os/os2/file_stream.odin @@ -15,7 +15,7 @@ to_reader :: to_stream @(private) -error_to_io_error :: proc(ferr: Error) -> io.Error { +error_to_io_Platform_Error :: proc(ferr: Error) -> io.Error { if ferr == nil { return .None } diff --git a/core/os/os2/process.odin b/core/os/os2/process.odin index 3f3e64668..f1309e468 100644 --- a/core/os/os2/process.odin +++ b/core/os/os2/process.odin @@ -370,7 +370,7 @@ Process_State :: struct { timeout (if specified) has reached zero. If the timeout is `TIMEOUT_INFINITE`, no timeout restriction is imposed and the procedure can block indefinately. - If the timeout has expired, the `General_Error.Timeout` is returned as + If the timeout has expired, the `GeneralPlatform_Error.Timeout` is returned as the error. If an error is returned for any other reason, other than timeout, the diff --git a/core/os/os2/process_windows.odin b/core/os/os2/process_windows.odin index 47fd62401..57f162eab 100644 --- a/core/os/os2/process_windows.odin +++ b/core/os/os2/process_windows.odin @@ -101,7 +101,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator if selection >= {.PPid, .Priority} { entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { - err = General_Error.Not_Exist + err = GeneralPlatform_Error.Not_Exist return } if .PPid in selection { @@ -147,7 +147,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator } if process_info.PebBaseAddress == nil { // Not sure what the error is - err = General_Error.Unsupported + err = GeneralPlatform_Error.Unsupported return } process_peb: win32.PEB @@ -210,7 +210,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields if selection >= {.PPid, .Priority} { // snap process entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { - err = General_Error.Not_Exist + err = GeneralPlatform_Error.Not_Exist return } if .PPid in selection { @@ -239,7 +239,7 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields } if process_info.PebBaseAddress == nil { // Not sure what the error is - err = General_Error.Unsupported + err = GeneralPlatform_Error.Unsupported return } @@ -301,7 +301,7 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime if selection >= {.PPid, .Priority} { // snap process entry, entry_err := _process_entry_by_pid(info.pid) if entry_err != nil { - err = General_Error.Not_Exist + err = GeneralPlatform_Error.Not_Exist return } if .PPid in selection { @@ -459,7 +459,7 @@ _process_wait :: proc(process: Process, timeout: time.Duration) -> (process_stat } return case win32.WAIT_TIMEOUT: - err = General_Error.Timeout + err = GeneralPlatform_Error.Timeout return case: err = _get_platform_error() @@ -508,7 +508,7 @@ _process_entry_by_pid :: proc(pid: int) -> (entry: win32.PROCESSENTRY32W, err: E } status = win32.Process32NextW(snap, &entry) } - err = General_Error.Not_Exist + err = GeneralPlatform_Error.Not_Exist return } diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index e3748cce4..f72529682 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -10,146 +10,257 @@ import "core:c" Handle :: distinct i32 File_Time :: distinct u64 -Errno :: distinct int INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno : 0 -EPERM: Errno : 1 /* Operation not permitted */ -ENOENT: Errno : 2 /* No such file or directory */ -ESRCH: Errno : 3 /* No such process */ -EINTR: Errno : 4 /* Interrupted system call */ -EIO: Errno : 5 /* Input/output error */ -ENXIO: Errno : 6 /* Device not configured */ -E2BIG: Errno : 7 /* Argument list too long */ -ENOEXEC: Errno : 8 /* Exec format error */ -EBADF: Errno : 9 /* Bad file descriptor */ -ECHILD: Errno : 10 /* No child processes */ -EDEADLK: Errno : 11 /* Resource deadlock avoided */ -ENOMEM: Errno : 12 /* Cannot allocate memory */ -EACCES: Errno : 13 /* Permission denied */ -EFAULT: Errno : 14 /* Bad address */ -ENOTBLK: Errno : 15 /* Block device required */ -EBUSY: Errno : 16 /* Device / Resource busy */ -EEXIST: Errno : 17 /* File exists */ -EXDEV: Errno : 18 /* Cross-device link */ -ENODEV: Errno : 19 /* Operation not supported by device */ -ENOTDIR: Errno : 20 /* Not a directory */ -EISDIR: Errno : 21 /* Is a directory */ -EINVAL: Errno : 22 /* Invalid argument */ -ENFILE: Errno : 23 /* Too many open files in system */ -EMFILE: Errno : 24 /* Too many open files */ -ENOTTY: Errno : 25 /* Inappropriate ioctl for device */ -ETXTBSY: Errno : 26 /* Text file busy */ -EFBIG: Errno : 27 /* File too large */ -ENOSPC: Errno : 28 /* No space left on device */ -ESPIPE: Errno : 29 /* Illegal seek */ -EROFS: Errno : 30 /* Read-only file system */ -EMLINK: Errno : 31 /* Too many links */ -EPIPE: Errno : 32 /* Broken pipe */ - -/* math software */ -EDOM: Errno : 33 /* Numerical argument out of domain */ -ERANGE: Errno : 34 /* Result too large */ - -/* non-blocking and interrupt i/o */ -EAGAIN: Errno : 35 /* Resource temporarily unavailable */ -EWOULDBLOCK: Errno : EAGAIN /* Operation would block */ -EINPROGRESS: Errno : 36 /* Operation now in progress */ -EALREADY: Errno : 37 /* Operation already in progress */ - -/* ipc/network software -- argument errors */ -ENOTSOCK: Errno : 38 /* Socket operation on non-socket */ -EDESTADDRREQ: Errno : 39 /* Destination address required */ -EMSGSIZE: Errno : 40 /* Message too long */ -EPROTOTYPE: Errno : 41 /* Protocol wrong type for socket */ -ENOPROTOOPT: Errno : 42 /* Protocol not available */ -EPROTONOSUPPORT: Errno : 43 /* Protocol not supported */ -ESOCKTNOSUPPORT: Errno : 44 /* Socket type not supported */ -ENOTSUP: Errno : 45 /* Operation not supported */ -EOPNOTSUPP:: ENOTSUP -EPFNOSUPPORT: Errno : 46 /* Protocol family not supported */ -EAFNOSUPPORT: Errno : 47 /* Address family not supported by protocol family */ -EADDRINUSE: Errno : 48 /* Address already in use */ -EADDRNOTAVAIL: Errno : 49 /* Can't assign requested address */ - -/* ipc/network software -- operational errors */ -ENETDOWN: Errno : 50 /* Network is down */ -ENETUNREACH: Errno : 51 /* Network is unreachable */ -ENETRESET: Errno : 52 /* Network dropped connection on reset */ -ECONNABORTED: Errno : 53 /* Software caused connection abort */ -ECONNRESET: Errno : 54 /* Connection reset by peer */ -ENOBUFS: Errno : 55 /* No buffer space available */ -EISCONN: Errno : 56 /* Socket is already connected */ -ENOTCONN: Errno : 57 /* Socket is not connected */ -ESHUTDOWN: Errno : 58 /* Can't send after socket shutdown */ -ETOOMANYREFS: Errno : 59 /* Too many references: can't splice */ -ETIMEDOUT: Errno : 60 /* Operation timed out */ -ECONNREFUSED: Errno : 61 /* Connection refused */ - -ELOOP: Errno : 62 /* Too many levels of symbolic links */ -ENAMETOOLONG: Errno : 63 /* File name too long */ - -/* should be rearranged */ -EHOSTDOWN: Errno : 64 /* Host is down */ -EHOSTUNREACH: Errno : 65 /* No route to host */ -ENOTEMPTY: Errno : 66 /* Directory not empty */ - -/* quotas & mush */ -EPROCLIM: Errno : 67 /* Too many processes */ -EUSERS: Errno : 68 /* Too many users */ -EDQUOT: Errno : 69 /* Disc quota exceeded */ - -/* Network File System */ -ESTALE: Errno : 70 /* Stale NFS file handle */ -EREMOTE: Errno : 71 /* Too many levels of remote in path */ -EBADRPC: Errno : 72 /* RPC struct is bad */ -ERPCMISMATCH: Errno : 73 /* RPC version wrong */ -EPROGUNAVAIL: Errno : 74 /* RPC prog. not avail */ -EPROGMISMATCH: Errno : 75 /* Program version wrong */ -EPROCUNAVAIL: Errno : 76 /* Bad procedure for program */ - -ENOLCK: Errno : 77 /* No locks available */ -ENOSYS: Errno : 78 /* Function not implemented */ - -EFTYPE: Errno : 79 /* Inappropriate file type or format */ -EAUTH: Errno : 80 /* Authentication error */ -ENEEDAUTH: Errno : 81 /* Need authenticator */ - -/* Intelligent device errors */ -EPWROFF: Errno : 82 /* Device power is off */ -EDEVERR: Errno : 83 /* Device error, e.g. paper out */ -EOVERFLOW: Errno : 84 /* Value too large to be stored in data type */ - -/* Program loading errors */ -EBADEXEC: Errno : 85 /* Bad executable */ -EBADARCH: Errno : 86 /* Bad CPU type in executable */ -ESHLIBVERS: Errno : 87 /* Shared library version mismatch */ -EBADMACHO: Errno : 88 /* Malformed Macho file */ - -ECANCELED: Errno : 89 /* Operation canceled */ - -EIDRM: Errno : 90 /* Identifier removed */ -ENOMSG: Errno : 91 /* No message of desired type */ -EILSEQ: Errno : 92 /* Illegal byte sequence */ -ENOATTR: Errno : 93 /* Attribute not found */ - -EBADMSG: Errno : 94 /* Bad message */ -EMULTIHOP: Errno : 95 /* Reserved */ -ENODATA: Errno : 96 /* No message available on STREAM */ -ENOLINK: Errno : 97 /* Reserved */ -ENOSR: Errno : 98 /* No STREAM resources */ -ENOSTR: Errno : 99 /* Not a STREAM */ -EPROTO: Errno : 100 /* Protocol error */ -ETIME: Errno : 101 /* STREAM ioctl timeout */ - -ENOPOLICY: Errno : 103 /* No such policy registered */ - -ENOTRECOVERABLE: Errno : 104 /* State not recoverable */ -EOWNERDEAD: Errno : 105 /* Previous owner died */ - -EQFULL: Errno : 106 /* Interface output queue is full */ -ELAST: Errno : 106 /* Must be equal largest errno */ +_Platform_Error :: enum i32 { + NONE = 0, + EPERM = 1, /* Operation not permitted */ + ENOENT = 2, /* No such file or directory */ + ESRCH = 3, /* No such process */ + EINTR = 4, /* Interrupted system call */ + EIO = 5, /* Input/output error */ + ENXIO = 6, /* Device not configured */ + E2BIG = 7, /* Argument list too long */ + ENOEXEC = 8, /* Exec format error */ + EBADF = 9, /* Bad file descriptor */ + ECHILD = 10, /* No child processes */ + EDEADLK = 11, /* Resource deadlock avoided */ + ENOMEM = 12, /* Cannot allocate memory */ + EACCES = 13, /* Permission denied */ + EFAULT = 14, /* Bad address */ + ENOTBLK = 15, /* Block device required */ + EBUSY = 16, /* Device / Resource busy */ + EEXIST = 17, /* File exists */ + EXDEV = 18, /* Cross-device link */ + ENODEV = 19, /* Operation not supported by device */ + ENOTDIR = 20, /* Not a directory */ + EISDIR = 21, /* Is a directory */ + EINVAL = 22, /* Invalid argument */ + ENFILE = 23, /* Too many open files in system */ + EMFILE = 24, /* Too many open files */ + ENOTTY = 25, /* Inappropriate ioctl for device */ + ETXTBSY = 26, /* Text file busy */ + EFBIG = 27, /* File too large */ + ENOSPC = 28, /* No space left on device */ + ESPIPE = 29, /* Illegal seek */ + EROFS = 30, /* Read-only file system */ + EMLINK = 31, /* Too many links */ + EPIPE = 32, /* Broken pipe */ + + /* math software */ + EDOM = 33, /* Numerical argument out of domain */ + ERANGE = 34, /* Result too large */ + + /* non-blocking and interrupt i/o */ + EAGAIN = 35, /* Resource temporarily unavailable */ + EWOULDBLOCK = EAGAIN, /* Operation would block */ + EINPROGRESS = 36, /* Operation now in progress */ + EALREADY = 37, /* Operation already in progress */ + + /* ipc/network software -- argument errors */ + ENOTSOCK = 38, /* Socket operation on non-socket */ + EDESTADDRREQ = 39, /* Destination address required */ + EMSGSIZE = 40, /* Message too long */ + EPROTOTYPE = 41, /* Protocol wrong type for socket */ + ENOPROTOOPT = 42, /* Protocol not available */ + EPROTONOSUPPOR = 43, /* Protocol not supported */ + ESOCKTNOSUPPOR = 44, /* Socket type not supported */ + ENOTSUP = 45, /* Operation not supported */ + EOPNOTSUPP = ENOTSUP, + EPFNOSUPPORT = 46, /* Protocol family not supported */ + EAFNOSUPPORT = 47, /* Address family not supported by protocol family */ + EADDRINUSE = 48, /* Address already in use */ + EADDRNOTAVAIL = 49, /* Can't assign requested address */ + + /* ipc/network software -- operational errors */ + ENETDOWN = 50, /* Network is down */ + ENETUNREAC = 51, /* Network is unreachable */ + ENETRESET = 52, /* Network dropped connection on reset */ + ECONNABORTE = 53, /* Software caused connection abort */ + ECONNRESET = 54, /* Connection reset by peer */ + ENOBUFS = 55, /* No buffer space available */ + EISCONN = 56, /* Socket is already connected */ + ENOTCONN = 57, /* Socket is not connected */ + ESHUTDOWN = 58, /* Can't send after socket shutdown */ + ETOOMANYREF = 59, /* Too many references: can't splice */ + ETIMEDOUT = 60, /* Operation timed out */ + ECONNREFUSE = 61, /* Connection refused */ + + ELOOP = 62, /* Too many levels of symbolic links */ + ENAMETOOLON = 63, /* File name too long */ + + /* should be rearranged */ + EHOSTDOWN = 64, /* Host is down */ + EHOSTUNREAC = 65, /* No route to host */ + ENOTEMPTY = 66, /* Directory not empty */ + + /* quotas & mush */ + EPROCLIM = 67, /* Too many processes */ + EUSERS = 68, /* Too many users */ + EDQUOT = 69, /* Disc quota exceeded */ + + /* Network File System */ + ESTALE = 70, /* Stale NFS file handle */ + EREMOTE = 71, /* Too many levels of remote in path */ + EBADRPC = 72, /* RPC struct is bad */ + ERPCMISMATC = 73, /* RPC version wrong */ + EPROGUNAVAI = 74, /* RPC prog. not avail */ + EPROGMISMATC = 75, /* Program version wrong */ + EPROCUNAVAI = 76, /* Bad procedure for program */ + + ENOLC = 77, /* No locks available */ + ENOSY = 78, /* Function not implemented */ + + EFTYP = 79, /* Inappropriate file type or format */ + EAUT = 80, /* Authentication error */ + ENEEDAUT = 81, /* Need authenticator */ + + /* Intelligent device errors */ + EPWROF = 82, /* Device power is off */ + EDEVER = 83, /* Device error, e.g. paper out */ + EOVERFLO = 84, /* Value too large to be stored in data type */ + + /* Program loading errors */ + EBADEXE = 85, /* Bad executable */ + EBADARC = 86, /* Bad CPU type in executable */ + ESHLIBVER = 87, /* Shared library version mismatch */ + EBADMACH = 88, /* Malformed Macho file */ + + ECANCELE = 89, /* Operation canceled */ + + EIDRM = 90, /* Identifier removed */ + ENOMSG = 91, /* No message of desired type */ + EILSEQ = 92, /* Illegal byte sequence */ + ENOATT = 93, /* Attribute not found */ + + EBADMS = 94, /* Bad message */ + EMULTIHO = 95, /* Reserved */ + ENODAT = 96, /* No message available on STREAM */ + ENOLIN = 97, /* Reserved */ + ENOSR = 98, /* No STREAM resources */ + ENOSTR = 99, /* Not a STREAM */ + EPROTO = 100, /* Protocol error */ + ETIME = 101, /* STREAM ioctl timeout */ + + ENOPOLIC = 103, /* No such policy registered */ + + ENOTRECOVERABL = 104, /* State not recoverable */ + EOWNERDEAD = 105, /* Previous owner died */ + + EQFUL = 106, /* Interface output queue is full */ + ELAS = 106, /* Must be equal largest errno */ +} + + +EPERM :: Platform_Error.EPERM +ENOENT :: Platform_Error.ENOENT +ESRCH :: Platform_Error.ESRCH +EINTR :: Platform_Error.EINTR +EIO :: Platform_Error.EIO +ENXIO :: Platform_Error.ENXIO +E2BIG :: Platform_Error.E2BIG +ENOEXEC :: Platform_Error.ENOEXEC +EBADF :: Platform_Error.EBADF +ECHILD :: Platform_Error.ECHILD +EDEADLK :: Platform_Error.EDEADLK +ENOMEM :: Platform_Error.ENOMEM +EACCES :: Platform_Error.EACCES +EFAULT :: Platform_Error.EFAULT +ENOTBLK :: Platform_Error.ENOTBLK +EBUSY :: Platform_Error.EBUSY +EEXIST :: Platform_Error.EEXIST +EXDEV :: Platform_Error.EXDEV +ENODEV :: Platform_Error.ENODEV +ENOTDIR :: Platform_Error.ENOTDIR +EISDIR :: Platform_Error.EISDIR +EINVAL :: Platform_Error.EINVAL +ENFILE :: Platform_Error.ENFILE +EMFILE :: Platform_Error.EMFILE +ENOTTY :: Platform_Error.ENOTTY +ETXTBSY :: Platform_Error.ETXTBSY +EFBIG :: Platform_Error.EFBIG +ENOSPC :: Platform_Error.ENOSPC +ESPIPE :: Platform_Error.ESPIPE +EROFS :: Platform_Error.EROFS +EMLINK :: Platform_Error.EMLINK +EPIPE :: Platform_Error.EPIPE +EDOM :: Platform_Error.EDOM +ERANGE :: Platform_Error.ERANGE +EAGAIN :: Platform_Error.EAGAIN +EWOULDBLOCK :: Platform_Error.EWOULDBLOCK +EINPROGRESS :: Platform_Error.EINPROGRESS +EALREADY :: Platform_Error.EALREADY +ENOTSOCK :: Platform_Error.ENOTSOCK +EDESTADDRREQ :: Platform_Error.EDESTADDRREQ +EMSGSIZE :: Platform_Error.EMSGSIZE +EPROTOTYPE :: Platform_Error.EPROTOTYPE +ENOPROTOOPT :: Platform_Error.ENOPROTOOPT +EPROTONOSUPPOR :: Platform_Error.EPROTONOSUPPOR +ESOCKTNOSUPPOR :: Platform_Error.ESOCKTNOSUPPOR +ENOTSUP :: Platform_Error.ENOTSUP +EOPNOTSUPP :: Platform_Error.EOPNOTSUPP +EPFNOSUPPORT :: Platform_Error.EPFNOSUPPORT +EAFNOSUPPORT :: Platform_Error.EAFNOSUPPORT +EADDRINUSE :: Platform_Error.EADDRINUSE +EADDRNOTAVAIL :: Platform_Error.EADDRNOTAVAIL +ENETDOWN :: Platform_Error.ENETDOWN +ENETUNREAC :: Platform_Error.ENETUNREAC +ENETRESET :: Platform_Error.ENETRESET +ECONNABORTE :: Platform_Error.ECONNABORTE +ECONNRESET :: Platform_Error.ECONNRESET +ENOBUFS :: Platform_Error.ENOBUFS +EISCONN :: Platform_Error.EISCONN +ENOTCONN :: Platform_Error.ENOTCONN +ESHUTDOWN :: Platform_Error.ESHUTDOWN +ETOOMANYREF :: Platform_Error.ETOOMANYREF +ETIMEDOUT :: Platform_Error.ETIMEDOUT +ECONNREFUSE :: Platform_Error.ECONNREFUSE +ELOOP :: Platform_Error.ELOOP +ENAMETOOLON :: Platform_Error.ENAMETOOLON +EHOSTDOWN :: Platform_Error.EHOSTDOWN +EHOSTUNREAC :: Platform_Error.EHOSTUNREAC +ENOTEMPTY :: Platform_Error.ENOTEMPTY +EPROCLIM :: Platform_Error.EPROCLIM +EUSERS :: Platform_Error.EUSERS +EDQUOT :: Platform_Error.EDQUOT +ESTALE :: Platform_Error.ESTALE +EREMOTE :: Platform_Error.EREMOTE +EBADRPC :: Platform_Error.EBADRPC +ERPCMISMATC :: Platform_Error.ERPCMISMATC +EPROGUNAVAI :: Platform_Error.EPROGUNAVAI +EPROGMISMATC :: Platform_Error.EPROGMISMATC +EPROCUNAVAI :: Platform_Error.EPROCUNAVAI +ENOLC :: Platform_Error.ENOLC +ENOSY :: Platform_Error.ENOSY +EFTYP :: Platform_Error.EFTYP +EAUT :: Platform_Error.EAUT +ENEEDAUT :: Platform_Error.ENEEDAUT +EPWROF :: Platform_Error.EPWROF +EDEVER :: Platform_Error.EDEVER +EOVERFLO :: Platform_Error.EOVERFLO +EBADEXE :: Platform_Error.EBADEXE +EBADARC :: Platform_Error.EBADARC +ESHLIBVER :: Platform_Error.ESHLIBVER +EBADMACH :: Platform_Error.EBADMACH +ECANCELE :: Platform_Error.ECANCELE +EIDRM :: Platform_Error.EIDRM +ENOMSG :: Platform_Error.ENOMSG +EILSEQ :: Platform_Error.EILSEQ +ENOATT :: Platform_Error.ENOATT +EBADMS :: Platform_Error.EBADMS +EMULTIHO :: Platform_Error.EMULTIHO +ENODAT :: Platform_Error.ENODAT +ENOLIN :: Platform_Error.ENOLIN +ENOSR :: Platform_Error.ENOSR +ENOSTR :: Platform_Error.ENOSTR +EPROTO :: Platform_Error.EPROTO +ETIME :: Platform_Error.ETIME +ENOPOLIC :: Platform_Error.ENOPOLIC +ENOTRECOVERABL :: Platform_Error.ENOTRECOVERABL +EOWNERDEAD :: Platform_Error.EOWNERDEAD +EQFUL :: Platform_Error.EQFUL +ELAS :: Platform_Error.ELAS O_RDONLY :: 0x0000 O_WRONLY :: 0x0001 @@ -524,12 +635,12 @@ foreign dl { @(link_name="dlerror") _unix_dlerror :: proc() -> cstring --- } -get_last_error :: proc "contextless" () -> int { - return int(__error()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__error()^) } get_last_error_string :: proc() -> string { - return cast(string)_darwin_string_error(cast(c.int)get_last_error()) + return string(_darwin_string_error(__error()^)) } @@ -548,7 +659,7 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno cstr := strings.clone_to_cstring(path, context.temp_allocator) handle := _unix_open(cstr, i32(flags), u16(mode)) if handle == -1 { - return INVALID_HANDLE, cast(Errno)get_last_error() + return INVALID_HANDLE, get_last_error() } /* diff --git a/core/os/os_essence.odin b/core/os/os_essence.odin index e4281f6c9..98abb432d 100644 --- a/core/os/os_essence.odin +++ b/core/os/os_essence.odin @@ -2,54 +2,54 @@ package os import "core:sys/es" -Handle :: distinct int; -Errno :: distinct int; +Handle :: distinct int +_Platform_Error :: enum i32 {NONE} -ERROR_NONE :: (Errno) (es.SUCCESS); +ERROR_NONE :: Errno(es.SUCCESS) -O_RDONLY :: 0x1; -O_WRONLY :: 0x2; -O_CREATE :: 0x4; -O_TRUNC :: 0x8; +O_RDONLY :: 0x1 +O_WRONLY :: 0x2 +O_CREATE :: 0x4 +O_TRUNC :: 0x8 -stderr : Handle = 0; +stderr : Handle = 0 current_thread_id :: proc "contextless" () -> int { - return (int) (es.ThreadGetID(es.CURRENT_THREAD)); + return (int) (es.ThreadGetID(es.CURRENT_THREAD)) } heap_alloc :: proc(size: int, zero_memory := true) -> rawptr { - return es.HeapAllocate(size, zero_memory); + return es.HeapAllocate(size, zero_memory) } heap_free :: proc(ptr: rawptr) { - es.HeapFree(ptr); + es.HeapFree(ptr) } heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { - return es.HeapReallocate(ptr, new_size, false); + return es.HeapReallocate(ptr, new_size, false) } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { - return (Handle) (0), (Errno) (1); + return (Handle) (0), (Errno) (1) } close :: proc(fd: Handle) -> Errno { - return (Errno) (1); + return (Errno) (1) } file_size :: proc(fd: Handle) -> (i64, Errno) { - return (i64) (0), (Errno) (1); + return (i64) (0), (Errno) (1) } read :: proc(fd: Handle, data: []byte) -> (int, Errno) { - return (int) (0), (Errno) (1); + return (int) (0), (Errno) (1) } write :: proc(fd: Handle, data: []u8) -> (int, Errno) { - return (int) (0), (Errno) (1); + return (int) (0), (Errno) (1) } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { - return (i64) (0), (Errno) (1); + return (i64) (0), (Errno) (1) } diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 36ada0948..7090a7773 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -9,105 +9,200 @@ import "core:c" Handle :: distinct i32 File_Time :: distinct u64 -Errno :: distinct i32 INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno : 0 -EPERM: Errno : 1 -ENOENT: Errno : 2 -ESRCH: Errno : 3 -EINTR: Errno : 4 -EIO: Errno : 5 -ENXIO: Errno : 6 -E2BIG: Errno : 7 -ENOEXEC: Errno : 8 -EBADF: Errno : 9 -ECHILD: Errno : 10 -EBEADLK: Errno : 11 -ENOMEM: Errno : 12 -EACCESS: Errno : 13 -EFAULT: Errno : 14 -ENOTBLK: Errno : 15 -EBUSY: Errno : 16 -EEXIST: Errno : 17 -EXDEV: Errno : 18 -ENODEV: Errno : 19 -ENOTDIR: Errno : 20 -EISDIR: Errno : 21 -EINVAL: Errno : 22 -ENFILE: Errno : 23 -EMFILE: Errno : 24 -ENOTTY: Errno : 25 -ETXTBSY: Errno : 26 -EFBIG: Errno : 27 -ENOSPC: Errno : 28 -ESPIPE: Errno : 29 -EROFS: Errno : 30 -EMLINK: Errno : 31 -EPIPE: Errno : 32 -EDOM: Errno : 33 -ERANGE: Errno : 34 /* Result too large */ -EAGAIN: Errno : 35 -EINPROGRESS: Errno : 36 -EALREADY: Errno : 37 -ENOTSOCK: Errno : 38 -EDESTADDRREQ: Errno : 39 -EMSGSIZE: Errno : 40 -EPROTOTYPE: Errno : 41 -ENOPROTOOPT: Errno : 42 -EPROTONOSUPPORT: Errno : 43 -ESOCKTNOSUPPORT: Errno : 44 -EOPNOTSUPP: Errno : 45 -EPFNOSUPPORT: Errno : 46 -EAFNOSUPPORT: Errno : 47 -EADDRINUSE: Errno : 48 -EADDRNOTAVAIL: Errno : 49 -ENETDOWN: Errno : 50 -ENETUNREACH: Errno : 51 -ENETRESET: Errno : 52 -ECONNABORTED: Errno : 53 -ECONNRESET: Errno : 54 -ENOBUFS: Errno : 55 -EISCONN: Errno : 56 -ENOTCONN: Errno : 57 -ESHUTDOWN: Errno : 58 -ETIMEDOUT: Errno : 60 -ECONNREFUSED: Errno : 61 -ELOOP: Errno : 62 -ENAMETOOLING: Errno : 63 -EHOSTDOWN: Errno : 64 -EHOSTUNREACH: Errno : 65 -ENOTEMPTY: Errno : 66 -EPROCLIM: Errno : 67 -EUSERS: Errno : 68 -EDQUOT: Errno : 69 -ESTALE: Errno : 70 -EBADRPC: Errno : 72 -ERPCMISMATCH: Errno : 73 -EPROGUNAVAIL: Errno : 74 -EPROGMISMATCH: Errno : 75 -EPROCUNAVAIL: Errno : 76 -ENOLCK: Errno : 77 -ENOSYS: Errno : 78 -EFTYPE: Errno : 79 -EAUTH: Errno : 80 -ENEEDAUTH: Errno : 81 -EIDRM: Errno : 82 -ENOMSG: Errno : 83 -EOVERFLOW: Errno : 84 -ECANCELED: Errno : 85 -EILSEQ: Errno : 86 -ENOATTR: Errno : 87 -EDOOFUS: Errno : 88 -EBADMSG: Errno : 89 -EMULTIHOP: Errno : 90 -ENOLINK: Errno : 91 -EPROTO: Errno : 92 -ENOTCAPABLE: Errno : 93 -ECAPMODE: Errno : 94 -ENOTRECOVERABLE: Errno : 95 -EOWNERDEAD: Errno : 96 +_Platform_Error :: enum i32 { + NONE = 0, + EPERM = 1, + ENOENT = 2, + ESRCH = 3, + EINTR = 4, + EIO = 5, + ENXIO = 6, + E2BIG = 7, + ENOEXEC = 8, + EBADF = 9, + ECHILD = 10, + EBEADLK = 11, + ENOMEM = 12, + EACCESS = 13, + EFAULT = 14, + ENOTBLK = 15, + 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, + EDOM = 33, + ERANGE = 34, /* Result too large */ + EAGAIN = 35, + EINPROGRESS = 36, + EALREADY = 37, + ENOTSOCK = 38, + EDESTADDRREQ = 39, + EMSGSIZE = 40, + EPROTOTYPE = 41, + ENOPROTOOPT = 42, + EPROTONOSUPPORT = 43, + ESOCKTNOSUPPORT = 44, + EOPNOTSUPP = 45, + EPFNOSUPPORT = 46, + EAFNOSUPPORT = 47, + EADDRINUSE = 48, + EADDRNOTAVAIL = 49, + ENETDOWN = 50, + ENETUNREACH = 51, + ENETRESET = 52, + ECONNABORTED = 53, + ECONNRESET = 54, + ENOBUFS = 55, + EISCONN = 56, + ENOTCONN = 57, + ESHUTDOWN = 58, + ETIMEDOUT = 60, + ECONNREFUSED = 61, + ELOOP = 62, + ENAMETOOLING = 63, + EHOSTDOWN = 64, + EHOSTUNREACH = 65, + ENOTEMPTY = 66, + EPROCLIM = 67, + EUSERS = 68, + EDQUOT = 69, + ESTALE = 70, + EBADRPC = 72, + ERPCMISMATCH = 73, + EPROGUNAVAIL = 74, + EPROGMISMATCH = 75, + EPROCUNAVAIL = 76, + ENOLCK = 77, + ENOSYS = 78, + EFTYPE = 79, + EAUTH = 80, + ENEEDAUTH = 81, + EIDRM = 82, + ENOMSG = 83, + EOVERFLOW = 84, + ECANCELED = 85, + EILSEQ = 86, + ENOATTR = 87, + EDOOFUS = 88, + EBADMSG = 89, + EMULTIHOP = 90, + ENOLINK = 91, + EPROTO = 92, + ENOTCAPABLE = 93, + ECAPMODE = 94, + ENOTRECOVERABLE = 95, + EOWNERDEAD = 96, +} +EPERM :: Platform_Error.EPERM +ENOENT :: Platform_Error.ENOENT +ESRCH :: Platform_Error.ESRCH +EINTR :: Platform_Error.EINTR +EIO :: Platform_Error.EIO +ENXIO :: Platform_Error.ENXIO +E2BIG :: Platform_Error.E2BIG +ENOEXEC :: Platform_Error.ENOEXEC +EBADF :: Platform_Error.EBADF +ECHILD :: Platform_Error.ECHILD +EBEADLK :: Platform_Error.EBEADLK +ENOMEM :: Platform_Error.ENOMEM +EACCESS :: Platform_Error.EACCESS +EFAULT :: Platform_Error.EFAULT +ENOTBLK :: Platform_Error.ENOTBLK +EBUSY :: Platform_Error.EBUSY +EEXIST :: Platform_Error.EEXIST +EXDEV :: Platform_Error.EXDEV +ENODEV :: Platform_Error.ENODEV +ENOTDIR :: Platform_Error.ENOTDIR +EISDIR :: Platform_Error.EISDIR +EINVAL :: Platform_Error.EINVAL +ENFILE :: Platform_Error.ENFILE +EMFILE :: Platform_Error.EMFILE +ENOTTY :: Platform_Error.ENOTTY +ETXTBSY :: Platform_Error.ETXTBSY +EFBIG :: Platform_Error.EFBIG +ENOSPC :: Platform_Error.ENOSPC +ESPIPE :: Platform_Error.ESPIPE +EROFS :: Platform_Error.EROFS +EMLINK :: Platform_Error.EMLINK +EPIPE :: Platform_Error.EPIPE +EDOM :: Platform_Error.EDOM +ERANGE :: Platform_Error.ERANGE +EAGAIN :: Platform_Error.EAGAIN +EINPROGRESS :: Platform_Error.EINPROGRESS +EALREADY :: Platform_Error.EALREADY +ENOTSOCK :: Platform_Error.ENOTSOCK +EDESTADDRREQ :: Platform_Error.EDESTADDRREQ +EMSGSIZE :: Platform_Error.EMSGSIZE +EPROTOTYPE :: Platform_Error.EPROTOTYPE +ENOPROTOOPT :: Platform_Error.ENOPROTOOPT +EPROTONOSUPPORT :: Platform_Error.EPROTONOSUPPORT +ESOCKTNOSUPPORT :: Platform_Error.ESOCKTNOSUPPORT +EOPNOTSUPP :: Platform_Error.EOPNOTSUPP +EPFNOSUPPORT :: Platform_Error.EPFNOSUPPORT +EAFNOSUPPORT :: Platform_Error.EAFNOSUPPORT +EADDRINUSE :: Platform_Error.EADDRINUSE +EADDRNOTAVAIL :: Platform_Error.EADDRNOTAVAIL +ENETDOWN :: Platform_Error.ENETDOWN +ENETUNREACH :: Platform_Error.ENETUNREACH +ENETRESET :: Platform_Error.ENETRESET +ECONNABORTED :: Platform_Error.ECONNABORTED +ECONNRESET :: Platform_Error.ECONNRESET +ENOBUFS :: Platform_Error.ENOBUFS +EISCONN :: Platform_Error.EISCONN +ENOTCONN :: Platform_Error.ENOTCONN +ESHUTDOWN :: Platform_Error.ESHUTDOWN +ETIMEDOUT :: Platform_Error.ETIMEDOUT +ECONNREFUSED :: Platform_Error.ECONNREFUSED +ELOOP :: Platform_Error.ELOOP +ENAMETOOLING :: Platform_Error.ENAMETOOLING +EHOSTDOWN :: Platform_Error.EHOSTDOWN +EHOSTUNREACH :: Platform_Error.EHOSTUNREACH +ENOTEMPTY :: Platform_Error.ENOTEMPTY +EPROCLIM :: Platform_Error.EPROCLIM +EUSERS :: Platform_Error.EUSERS +EDQUOT :: Platform_Error.EDQUOT +ESTALE :: Platform_Error.ESTALE +EBADRPC :: Platform_Error.EBADRPC +ERPCMISMATCH :: Platform_Error.ERPCMISMATCH +EPROGUNAVAIL :: Platform_Error.EPROGUNAVAIL +EPROGMISMATCH :: Platform_Error.EPROGMISMATCH +EPROCUNAVAIL :: Platform_Error.EPROCUNAVAIL +ENOLCK :: Platform_Error.ENOLCK +ENOSYS :: Platform_Error.ENOSYS +EFTYPE :: Platform_Error.EFTYPE +EAUTH :: Platform_Error.EAUTH +ENEEDAUTH :: Platform_Error.ENEEDAUTH +EIDRM :: Platform_Error.EIDRM +ENOMSG :: Platform_Error.ENOMSG +EOVERFLOW :: Platform_Error.EOVERFLOW +ECANCELED :: Platform_Error.ECANCELED +EILSEQ :: Platform_Error.EILSEQ +ENOATTR :: Platform_Error.ENOATTR +EDOOFUS :: Platform_Error.EDOOFUS +EBADMSG :: Platform_Error.EBADMSG +EMULTIHOP :: Platform_Error.EMULTIHOP +ENOLINK :: Platform_Error.ENOLINK +EPROTO :: Platform_Error.EPROTO +ENOTCAPABLE :: Platform_Error.ENOTCAPABLE +ECAPMODE :: Platform_Error.ECAPMODE +ENOTRECOVERABLE :: Platform_Error.ENOTRECOVERABLE +EOWNERDEAD :: Platform_Error.EOWNERDEAD O_RDONLY :: 0x00000 O_WRONLY :: 0x00001 @@ -324,8 +419,8 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } -get_last_error :: proc "contextless" () -> int { - return int(__errno_location()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__errno_location()^) } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index 06052fc42..03e2c5e64 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -10,16 +10,14 @@ import "core:sys/haiku" Handle :: i32 Pid :: i32 File_Time :: i64 -Errno :: i32 +_Platform_Error :: haiku.Errno MAX_PATH :: haiku.PATH_MAX -ENOSYS :: int(haiku.Errno.POSIX_ERROR_BASE) + 9 +ENOSYS :: _Platform_Error(i32(haiku.Errno.POSIX_ERROR_BASE) + 9) INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno: 0 - stdin: Handle = 0 stdout: Handle = 1 stderr: Handle = 2 @@ -183,8 +181,8 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } -get_last_error :: proc "contextless" () -> int { - return int(__error()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__error()^) } fork :: proc() -> (Pid, Errno) { @@ -391,8 +389,8 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { } defer _unix_free(path_ptr) - path_cstr := transmute(cstring)path_ptr - path = strings.clone( string(path_cstr) ) + path_cstr := cstring(path_ptr) + path = strings.clone(string(path_cstr)) return path, ERROR_NONE } diff --git a/core/os/os_js.odin b/core/os/os_js.odin index 8b61cb7ed..f27b13097 100644 --- a/core/os/os_js.odin +++ b/core/os/os_js.odin @@ -161,7 +161,40 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F Handle :: distinct uintptr File_Time :: distinct u64 -Errno :: distinct int + +_Platform_Error :: enum i32 { + NONE = 0, + FILE_NOT_FOUND = 2, + PATH_NOT_FOUND = 3, + ACCESS_DENIED = 5, + INVALID_HANDLE = 6, + NOT_ENOUGH_MEMORY = 8, + NO_MORE_FILES = 18, + HANDLE_EOF = 38, + NETNAME_DELETED = 64, + FILE_EXISTS = 80, + INVALID_PARAMETER = 87, + BROKEN_PIPE = 109, + BUFFER_OVERFLOW = 111, + INSUFFICIENT_BUFFER = 122, + MOD_NOT_FOUND = 126, + PROC_NOT_FOUND = 127, + DIR_NOT_EMPTY = 145, + ALREADY_EXISTS = 183, + ENVVAR_NOT_FOUND = 203, + MORE_DATA = 234, + OPERATION_ABORTED = 995, + IO_PENDING = 997, + NOT_FOUND = 1168, + PRIVILEGE_NOT_HELD = 1314, + WSAEACCES = 10013, + WSAECONNRESET = 10054, + + // Windows reserves errors >= 1<<29 for application use + FILE_IS_PIPE = 1<<29 + 0, + FILE_IS_NOT_DIR = 1<<29 + 1, + NEGATIVE_OFFSET = 1<<29 + 2, +} INVALID_HANDLE :: ~Handle(0) @@ -182,37 +215,36 @@ O_ASYNC :: 0x02000 O_CLOEXEC :: 0x80000 -ERROR_NONE: Errno : 0 -ERROR_FILE_NOT_FOUND: Errno : 2 -ERROR_PATH_NOT_FOUND: Errno : 3 -ERROR_ACCESS_DENIED: Errno : 5 -ERROR_INVALID_HANDLE: Errno : 6 -ERROR_NOT_ENOUGH_MEMORY: Errno : 8 -ERROR_NO_MORE_FILES: Errno : 18 -ERROR_HANDLE_EOF: Errno : 38 -ERROR_NETNAME_DELETED: Errno : 64 -ERROR_FILE_EXISTS: Errno : 80 -ERROR_INVALID_PARAMETER: Errno : 87 -ERROR_BROKEN_PIPE: Errno : 109 -ERROR_BUFFER_OVERFLOW: Errno : 111 -ERROR_INSUFFICIENT_BUFFER: Errno : 122 -ERROR_MOD_NOT_FOUND: Errno : 126 -ERROR_PROC_NOT_FOUND: Errno : 127 -ERROR_DIR_NOT_EMPTY: Errno : 145 -ERROR_ALREADY_EXISTS: Errno : 183 -ERROR_ENVVAR_NOT_FOUND: Errno : 203 -ERROR_MORE_DATA: Errno : 234 -ERROR_OPERATION_ABORTED: Errno : 995 -ERROR_IO_PENDING: Errno : 997 -ERROR_NOT_FOUND: Errno : 1168 -ERROR_PRIVILEGE_NOT_HELD: Errno : 1314 -WSAEACCES: Errno : 10013 -WSAECONNRESET: Errno : 10054 +ERROR_FILE_NOT_FOUND :: Platform_Error.FILE_NOT_FOUND +ERROR_PATH_NOT_FOUND :: Platform_Error.PATH_NOT_FOUND +ERROR_ACCESS_DENIED :: Platform_Error.ACCESS_DENIED +ERROR_INVALID_HANDLE :: Platform_Error.INVALID_HANDLE +ERROR_NOT_ENOUGH_MEMORY :: Platform_Error.NOT_ENOUGH_MEMORY +ERROR_NO_MORE_FILES :: Platform_Error.NO_MORE_FILES +ERROR_HANDLE_EOF :: Platform_Error.HANDLE_EOF +ERROR_NETNAME_DELETED :: Platform_Error.NETNAME_DELETED +ERROR_FILE_EXISTS :: Platform_Error.FILE_EXISTS +ERROR_INVALID_PARAMETER :: Platform_Error.INVALID_PARAMETER +ERROR_BROKEN_PIPE :: Platform_Error.BROKEN_PIPE +ERROR_BUFFER_OVERFLOW :: Platform_Error.BUFFER_OVERFLOW +ERROR_INSUFFICIENT_BUFFER :: Platform_Error.INSUFFICIENT_BUFFER +ERROR_MOD_NOT_FOUND :: Platform_Error.MOD_NOT_FOUND +ERROR_PROC_NOT_FOUND :: Platform_Error.PROC_NOT_FOUND +ERROR_DIR_NOT_EMPTY :: Platform_Error.DIR_NOT_EMPTY +ERROR_ALREADY_EXISTS :: Platform_Error.ALREADY_EXISTS +ERROR_ENVVAR_NOT_FOUND :: Platform_Error.ENVVAR_NOT_FOUND +ERROR_MORE_DATA :: Platform_Error.MORE_DATA +ERROR_OPERATION_ABORTED :: Platform_Error.OPERATION_ABORTED +ERROR_IO_PENDING :: Platform_Error.IO_PENDING +ERROR_NOT_FOUND :: Platform_Error.NOT_FOUND +ERROR_PRIVILEGE_NOT_HELD :: Platform_Error.PRIVILEGE_NOT_HELD +WSAEACCES :: Platform_Error.WSAEACCES +WSAECONNRESET :: Platform_Error.WSAECONNRESET // Windows reserves errors >= 1<<29 for application use -ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0 -ERROR_FILE_IS_NOT_DIR: Errno : 1<<29 + 1 -ERROR_NEGATIVE_OFFSET: Errno : 1<<29 + 2 +ERROR_FILE_IS_PIPE :: Platform_Error.FILE_IS_PIPE +ERROR_FILE_IS_NOT_DIR :: Platform_Error.FILE_IS_NOT_DIR +ERROR_NEGATIVE_OFFSET :: Platform_Error.NEGATIVE_OFFSET // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index ebc1b3600..ace24d26a 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -20,148 +20,148 @@ import "base:intrinsics" // all that about compatibility. But we don't want to push experimental changes // and have people's code break while it's still work in progress. import unix "core:sys/unix" +import linux "core:sys/linux" Handle :: distinct i32 Pid :: distinct i32 File_Time :: distinct u64 -Errno :: distinct i32 Socket :: distinct int INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno : 0 -EPERM: Errno : 1 -ENOENT: Errno : 2 -ESRCH: Errno : 3 -EINTR: Errno : 4 -EIO: Errno : 5 -ENXIO: Errno : 6 -EBADF: Errno : 9 -EAGAIN: Errno : 11 -ENOMEM: Errno : 12 -EACCES: Errno : 13 -EFAULT: Errno : 14 -EEXIST: Errno : 17 -ENODEV: Errno : 19 -ENOTDIR: Errno : 20 -EISDIR: Errno : 21 -EINVAL: Errno : 22 -ENFILE: Errno : 23 -EMFILE: Errno : 24 -ETXTBSY: Errno : 26 -EFBIG: Errno : 27 -ENOSPC: Errno : 28 -ESPIPE: Errno : 29 -EROFS: Errno : 30 -EPIPE: Errno : 32 - -ERANGE: Errno : 34 /* Result too large */ -EDEADLK: Errno : 35 /* Resource deadlock would occur */ -ENAMETOOLONG: Errno : 36 /* File name too long */ -ENOLCK: Errno : 37 /* No record locks available */ - -ENOSYS: Errno : 38 /* Invalid system call number */ - -ENOTEMPTY: Errno : 39 /* Directory not empty */ -ELOOP: Errno : 40 /* Too many symbolic links encountered */ -EWOULDBLOCK: Errno : EAGAIN /* Operation would block */ -ENOMSG: Errno : 42 /* No message of desired type */ -EIDRM: Errno : 43 /* Identifier removed */ -ECHRNG: Errno : 44 /* Channel number out of range */ -EL2NSYNC: Errno : 45 /* Level 2 not synchronized */ -EL3HLT: Errno : 46 /* Level 3 halted */ -EL3RST: Errno : 47 /* Level 3 reset */ -ELNRNG: Errno : 48 /* Link number out of range */ -EUNATCH: Errno : 49 /* Protocol driver not attached */ -ENOCSI: Errno : 50 /* No CSI structure available */ -EL2HLT: Errno : 51 /* Level 2 halted */ -EBADE: Errno : 52 /* Invalid exchange */ -EBADR: Errno : 53 /* Invalid request descriptor */ -EXFULL: Errno : 54 /* Exchange full */ -ENOANO: Errno : 55 /* No anode */ -EBADRQC: Errno : 56 /* Invalid request code */ -EBADSLT: Errno : 57 /* Invalid slot */ -EDEADLOCK: Errno : EDEADLK -EBFONT: Errno : 59 /* Bad font file format */ -ENOSTR: Errno : 60 /* Device not a stream */ -ENODATA: Errno : 61 /* No data available */ -ETIME: Errno : 62 /* Timer expired */ -ENOSR: Errno : 63 /* Out of streams resources */ -ENONET: Errno : 64 /* Machine is not on the network */ -ENOPKG: Errno : 65 /* Package not installed */ -EREMOTE: Errno : 66 /* Object is remote */ -ENOLINK: Errno : 67 /* Link has been severed */ -EADV: Errno : 68 /* Advertise error */ -ESRMNT: Errno : 69 /* Srmount error */ -ECOMM: Errno : 70 /* Communication error on send */ -EPROTO: Errno : 71 /* Protocol error */ -EMULTIHOP: Errno : 72 /* Multihop attempted */ -EDOTDOT: Errno : 73 /* RFS specific error */ -EBADMSG: Errno : 74 /* Not a data message */ -EOVERFLOW: Errno : 75 /* Value too large for defined data type */ -ENOTUNIQ: Errno : 76 /* Name not unique on network */ -EBADFD: Errno : 77 /* File descriptor in bad state */ -EREMCHG: Errno : 78 /* Remote address changed */ -ELIBACC: Errno : 79 /* Can not access a needed shared library */ -ELIBBAD: Errno : 80 /* Accessing a corrupted shared library */ -ELIBSCN: Errno : 81 /* .lib section in a.out corrupted */ -ELIBMAX: Errno : 82 /* Attempting to link in too many shared libraries */ -ELIBEXEC: Errno : 83 /* Cannot exec a shared library directly */ -EILSEQ: Errno : 84 /* Illegal byte sequence */ -ERESTART: Errno : 85 /* Interrupted system call should be restarted */ -ESTRPIPE: Errno : 86 /* Streams pipe error */ -EUSERS: Errno : 87 /* Too many users */ -ENOTSOCK: Errno : 88 /* Socket operation on non-socket */ -EDESTADDRREQ: Errno : 89 /* Destination address required */ -EMSGSIZE: Errno : 90 /* Message too long */ -EPROTOTYPE: Errno : 91 /* Protocol wrong type for socket */ -ENOPROTOOPT: Errno : 92 /* Protocol not available */ -EPROTONOSUPPORT:Errno : 93 /* Protocol not supported */ -ESOCKTNOSUPPORT:Errno : 94 /* Socket type not supported */ -EOPNOTSUPP: Errno : 95 /* Operation not supported on transport endpoint */ -EPFNOSUPPORT: Errno : 96 /* Protocol family not supported */ -EAFNOSUPPORT: Errno : 97 /* Address family not supported by protocol */ -EADDRINUSE: Errno : 98 /* Address already in use */ -EADDRNOTAVAIL: Errno : 99 /* Cannot assign requested address */ -ENETDOWN: Errno : 100 /* Network is down */ -ENETUNREACH: Errno : 101 /* Network is unreachable */ -ENETRESET: Errno : 102 /* Network dropped connection because of reset */ -ECONNABORTED: Errno : 103 /* Software caused connection abort */ -ECONNRESET: Errno : 104 /* Connection reset by peer */ -ENOBUFS: Errno : 105 /* No buffer space available */ -EISCONN: Errno : 106 /* Transport endpoint is already connected */ -ENOTCONN: Errno : 107 /* Transport endpoint is not connected */ -ESHUTDOWN: Errno : 108 /* Cannot send after transport endpoint shutdown */ -ETOOMANYREFS: Errno : 109 /* Too many references: cannot splice */ -ETIMEDOUT: Errno : 110 /* Connection timed out */ -ECONNREFUSED: Errno : 111 /* Connection refused */ -EHOSTDOWN: Errno : 112 /* Host is down */ -EHOSTUNREACH: Errno : 113 /* No route to host */ -EALREADY: Errno : 114 /* Operation already in progress */ -EINPROGRESS: Errno : 115 /* Operation now in progress */ -ESTALE: Errno : 116 /* Stale file handle */ -EUCLEAN: Errno : 117 /* Structure needs cleaning */ -ENOTNAM: Errno : 118 /* Not a XENIX named type file */ -ENAVAIL: Errno : 119 /* No XENIX semaphores available */ -EISNAM: Errno : 120 /* Is a named type file */ -EREMOTEIO: Errno : 121 /* Remote I/O error */ -EDQUOT: Errno : 122 /* Quota exceeded */ - -ENOMEDIUM: Errno : 123 /* No medium found */ -EMEDIUMTYPE: Errno : 124 /* Wrong medium type */ -ECANCELED: Errno : 125 /* Operation Canceled */ -ENOKEY: Errno : 126 /* Required key not available */ -EKEYEXPIRED: Errno : 127 /* Key has expired */ -EKEYREVOKED: Errno : 128 /* Key has been revoked */ -EKEYREJECTED: Errno : 129 /* Key was rejected by service */ +_Platform_Error :: linux.Errno +EPERM :: Platform_Error.EPERM +ENOENT :: Platform_Error.ENOENT +ESRCH :: Platform_Error.ESRCH +EINTR :: Platform_Error.EINTR +EIO :: Platform_Error.EIO +ENXIO :: Platform_Error.ENXIO +EBADF :: Platform_Error.EBADF +EAGAIN :: Platform_Error.EAGAIN +ENOMEM :: Platform_Error.ENOMEM +EACCES :: Platform_Error.EACCES +EFAULT :: Platform_Error.EFAULT +EEXIST :: Platform_Error.EEXIST +ENODEV :: Platform_Error.ENODEV +ENOTDIR :: Platform_Error.ENOTDIR +EISDIR :: Platform_Error.EISDIR +EINVAL :: Platform_Error.EINVAL +ENFILE :: Platform_Error.ENFILE +EMFILE :: Platform_Error.EMFILE +ETXTBSY :: Platform_Error.ETXTBSY +EFBIG :: Platform_Error.EFBIG +ENOSPC :: Platform_Error.ENOSPC +ESPIPE :: Platform_Error.ESPIPE +EROFS :: Platform_Error.EROFS +EPIPE :: Platform_Error.EPIPE + +ERANGE :: Platform_Error.ERANGE /* Result too large */ +EDEADLK :: Platform_Error.EDEADLK /* Resource deadlock would occur */ +ENAMETOOLONG :: Platform_Error.ENAMETOOLONG /* File name too long */ +ENOLCK :: Platform_Error.ENOLCK /* No record locks available */ + +ENOSYS :: Platform_Error.ENOSYS /* Invalid system call number */ + +ENOTEMPTY :: Platform_Error.ENOTEMPTY /* Directory not empty */ +ELOOP :: Platform_Error.ELOOP /* Too many symbolic links encountered */ +EWOULDBLOCK :: Platform_Error.EWOULDBLOCK /* Operation would block */ +ENOMSG :: Platform_Error.ENOMSG /* No message of desired type */ +EIDRM :: Platform_Error.EIDRM /* Identifier removed */ +ECHRNG :: Platform_Error.ECHRNG /* Channel number out of range */ +EL2NSYNC :: Platform_Error.EL2NSYNC /* Level 2 not synchronized */ +EL3HLT :: Platform_Error.EL3HLT /* Level 3 halted */ +EL3RST :: Platform_Error.EL3RST /* Level 3 reset */ +ELNRNG :: Platform_Error.ELNRNG /* Link number out of range */ +EUNATCH :: Platform_Error.EUNATCH /* Protocol driver not attached */ +ENOCSI :: Platform_Error.ENOCSI /* No CSI structure available */ +EL2HLT :: Platform_Error.EL2HLT /* Level 2 halted */ +EBADE :: Platform_Error.EBADE /* Invalid exchange */ +EBADR :: Platform_Error.EBADR /* Invalid request descriptor */ +EXFULL :: Platform_Error.EXFULL /* Exchange full */ +ENOANO :: Platform_Error.ENOANO /* No anode */ +EBADRQC :: Platform_Error.EBADRQC /* Invalid request code */ +EBADSLT :: Platform_Error.EBADSLT /* Invalid slot */ +EDEADLOCK :: Platform_Error.EDEADLOCK +EBFONT :: Platform_Error.EBFONT /* Bad font file format */ +ENOSTR :: Platform_Error.ENOSTR /* Device not a stream */ +ENODATA :: Platform_Error.ENODATA /* No data available */ +ETIME :: Platform_Error.ETIME /* Timer expired */ +ENOSR :: Platform_Error.ENOSR /* Out of streams resources */ +ENONET :: Platform_Error.ENONET /* Machine is not on the network */ +ENOPKG :: Platform_Error.ENOPKG /* Package not installed */ +EREMOTE :: Platform_Error.EREMOTE /* Object is remote */ +ENOLINK :: Platform_Error.ENOLINK /* Link has been severed */ +EADV :: Platform_Error.EADV /* Advertise error */ +ESRMNT :: Platform_Error.ESRMNT /* Srmount error */ +ECOMM :: Platform_Error.ECOMM /* Communication error on send */ +EPROTO :: Platform_Error.EPROTO /* Protocol error */ +EMULTIHOP :: Platform_Error.EMULTIHOP /* Multihop attempted */ +EDOTDOT :: Platform_Error.EDOTDOT /* RFS specific error */ +EBADMSG :: Platform_Error.EBADMSG /* Not a data message */ +EOVERFLOW :: Platform_Error.EOVERFLOW /* Value too large for defined data type */ +ENOTUNIQ :: Platform_Error.ENOTUNIQ /* Name not unique on network */ +EBADFD :: Platform_Error.EBADFD /* File descriptor in bad state */ +EREMCHG :: Platform_Error.EREMCHG /* Remote address changed */ +ELIBACC :: Platform_Error.ELIBACC /* Can not access a needed shared library */ +ELIBBAD :: Platform_Error.ELIBBAD /* Accessing a corrupted shared library */ +ELIBSCN :: Platform_Error.ELIBSCN /* .lib section in a.out corrupted */ +ELIBMAX :: Platform_Error.ELIBMAX /* Attempting to link in too many shared libraries */ +ELIBEXEC :: Platform_Error.ELIBEXEC /* Cannot exec a shared library directly */ +EILSEQ :: Platform_Error.EILSEQ /* Illegal byte sequence */ +ERESTART :: Platform_Error.ERESTART /* Interrupted system call should be restarted */ +ESTRPIPE :: Platform_Error.ESTRPIPE /* Streams pipe error */ +EUSERS :: Platform_Error.EUSERS /* Too many users */ +ENOTSOCK :: Platform_Error.ENOTSOCK /* Socket operation on non-socket */ +EDESTADDRREQ :: Platform_Error.EDESTADDRREQ /* Destination address required */ +EMSGSIZE :: Platform_Error.EMSGSIZE /* Message too long */ +EPROTOTYPE :: Platform_Error.EPROTOTYPE /* Protocol wrong type for socket */ +ENOPROTOOPT :: Platform_Error.ENOPROTOOPT /* Protocol not available */ +EPROTONOSUPPOR :: Platform_Error.EPROTONOSUPPORT /* Protocol not supported */ +ESOCKTNOSUPPOR :: Platform_Error.ESOCKTNOSUPPORT /* Socket type not supported */ +EOPNOTSUPP :: Platform_Error.EOPNOTSUPP /* Operation not supported on transport endpoint */ +EPFNOSUPPORT :: Platform_Error.EPFNOSUPPORT /* Protocol family not supported */ +EAFNOSUPPORT :: Platform_Error.EAFNOSUPPORT /* Address family not supported by protocol */ +EADDRINUSE :: Platform_Error.EADDRINUSE /* Address already in use */ +EADDRNOTAVAIL :: Platform_Error.EADDRNOTAVAIL /* Cannot assign requested address */ +ENETDOWN :: Platform_Error.ENETDOWN /* Network is down */ +ENETUNREACH :: Platform_Error.ENETUNREACH /* Network is unreachable */ +ENETRESET :: Platform_Error.ENETRESET /* Network dropped connection because of reset */ +ECONNABORTED :: Platform_Error.ECONNABORTED /* Software caused connection abort */ +ECONNRESET :: Platform_Error.ECONNRESET /* Connection reset by peer */ +ENOBUFS :: Platform_Error.ENOBUFS /* No buffer space available */ +EISCONN :: Platform_Error.EISCONN /* Transport endpoint is already connected */ +ENOTCONN :: Platform_Error.ENOTCONN /* Transport endpoint is not connected */ +ESHUTDOWN :: Platform_Error.ESHUTDOWN /* Cannot send after transport endpoint shutdown */ +ETOOMANYREFS :: Platform_Error.ETOOMANYREFS /* Too many references: cannot splice */ +ETIMEDOUT :: Platform_Error.ETIMEDOUT /* Connection timed out */ +ECONNREFUSED :: Platform_Error.ECONNREFUSED /* Connection refused */ +EHOSTDOWN :: Platform_Error.EHOSTDOWN /* Host is down */ +EHOSTUNREACH :: Platform_Error.EHOSTUNREACH /* No route to host */ +EALREADY :: Platform_Error.EALREADY /* Operation already in progress */ +EINPROGRESS :: Platform_Error.EINPROGRESS /* Operation now in progress */ +ESTALE :: Platform_Error.ESTALE /* Stale file handle */ +EUCLEAN :: Platform_Error.EUCLEAN /* Structure needs cleaning */ +ENOTNAM :: Platform_Error.ENOTNAM /* Not a XENIX named type file */ +ENAVAIL :: Platform_Error.ENAVAIL /* No XENIX semaphores available */ +EISNAM :: Platform_Error.EISNAM /* Is a named type file */ +EREMOTEIO :: Platform_Error.EREMOTEIO /* Remote I/O error */ +EDQUOT :: Platform_Error.EDQUOT /* Quota exceeded */ + +ENOMEDIUM :: Platform_Error.ENOMEDIUM /* No medium found */ +EMEDIUMTYPE :: Platform_Error.EMEDIUMTYPE /* Wrong medium type */ +ECANCELED :: Platform_Error.ECANCELED /* Operation Canceled */ +ENOKEY :: Platform_Error.ENOKEY /* Required key not available */ +EKEYEXPIRED :: Platform_Error.EKEYEXPIRED /* Key has expired */ +EKEYREVOKED :: Platform_Error.EKEYREVOKED /* Key has been revoked */ +EKEYREJECTED :: Platform_Error.EKEYREJECTED /* Key was rejected by service */ /* for robust mutexes */ -EOWNERDEAD: Errno : 130 /* Owner died */ -ENOTRECOVERABLE: Errno : 131 /* State not recoverable */ +EOWNERDEAD :: Platform_Error.EOWNERDEAD /* Owner died */ +ENOTRECOVERABLE :: Platform_Error.ENOTRECOVERABLE /* State not recoverable */ -ERFKILL: Errno : 132 /* Operation not possible due to RF-kill */ +ERFKILL :: Platform_Error.ERFKILL /* Operation not possible due to RF-kill */ -EHWPOISON: Errno : 133 /* Memory page has hardware error */ +EHWPOISON :: Platform_Error.EHWPOISON /* Memory page has hardware error */ ADDR_NO_RANDOMIZE :: 0x40000 @@ -520,8 +520,8 @@ _get_errno :: proc(res: int) -> Errno { } // get errno from libc -get_last_error :: proc "contextless" () -> int { - return int(__errno_location()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__errno_location()^) } personality :: proc(persona: u64) -> (Errno) { diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index da34a4168..b27daac3a 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -9,148 +9,287 @@ import "core:c" Handle :: distinct i32 File_Time :: distinct u64 -Errno :: distinct i32 INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno : 0 /* No error */ -EPERM: Errno : 1 /* Operation not permitted */ -ENOENT: Errno : 2 /* No such file or directory */ -EINTR: Errno : 4 /* Interrupted system call */ -ESRCH: Errno : 3 /* No such process */ -EIO: Errno : 5 /* Input/output error */ -ENXIO: Errno : 6 /* Device not configured */ -E2BIG: Errno : 7 /* Argument list too long */ -ENOEXEC: Errno : 8 /* Exec format error */ -EBADF: Errno : 9 /* Bad file descriptor */ -ECHILD: Errno : 10 /* No child processes */ -EDEADLK: Errno : 11 /* Resource deadlock avoided. 11 was EAGAIN */ -ENOMEM: Errno : 12 /* Cannot allocate memory */ -EACCES: Errno : 13 /* Permission denied */ -EFAULT: Errno : 14 /* Bad address */ -ENOTBLK: Errno : 15 /* Block device required */ -EBUSY: Errno : 16 /* Device busy */ -EEXIST: Errno : 17 /* File exists */ -EXDEV: Errno : 18 /* Cross-device link */ -ENODEV: Errno : 19 /* Operation not supported by device */ -ENOTDIR: Errno : 20 /* Not a directory */ -EISDIR: Errno : 21 /* Is a directory */ -EINVAL: Errno : 22 /* Invalid argument */ -ENFILE: Errno : 23 /* Too many open files in system */ -EMFILE: Errno : 24 /* Too many open files */ -ENOTTY: Errno : 25 /* Inappropriate ioctl for device */ -ETXTBSY: Errno : 26 /* Text file busy */ -EFBIG: Errno : 27 /* File too large */ -ENOSPC: Errno : 28 /* No space left on device */ -ESPIPE: Errno : 29 /* Illegal seek */ -EROFS: Errno : 30 /* Read-only file system */ -EMLINK: Errno : 31 /* Too many links */ -EPIPE: Errno : 32 /* Broken pipe */ +_Platform_Error :: enum i32 { + NONE = 0, + EPERM = 1, /* Operation not permitted */ + ENOENT = 2, /* No such file or directory */ + EINTR = 4, /* Interrupted system call */ + ESRCH = 3, /* No such process */ + EIO = 5, /* Input/output error */ + ENXIO = 6, /* Device not configured */ + E2BIG = 7, /* Argument list too long */ + ENOEXEC = 8, /* Exec format error */ + EBADF = 9, /* Bad file descriptor */ + ECHILD = 10, /* No child processes */ + EDEADLK = 11, /* Resource deadlock avoided. 11 was EAGAIN */ + ENOMEM = 12, /* Cannot allocate memory */ + EACCES = 13, /* Permission denied */ + EFAULT = 14, /* Bad address */ + ENOTBLK = 15, /* Block device required */ + EBUSY = 16, /* Device busy */ + EEXIST = 17, /* File exists */ + EXDEV = 18, /* Cross-device link */ + ENODEV = 19, /* Operation not supported by device */ + ENOTDIR = 20, /* Not a directory */ + EISDIR = 21, /* Is a directory */ + EINVAL = 22, /* Invalid argument */ + ENFILE = 23, /* Too many open files in system */ + EMFILE = 24, /* Too many open files */ + ENOTTY = 25, /* Inappropriate ioctl for device */ + ETXTBSY = 26, /* Text file busy */ + EFBIG = 27, /* File too large */ + ENOSPC = 28, /* No space left on device */ + ESPIPE = 29, /* Illegal seek */ + EROFS = 30, /* Read-only file system */ + EMLINK = 31, /* Too many links */ + EPIPE = 32, /* Broken pipe */ + + /* math software */ + EDOM = 33, /* Numerical argument out of domain */ + ERANGE = 34, /* Result too large or too small */ + + /* non-blocking and interrupt i/o */ + EAGAIN = 35, /* Resource temporarily unavailable */ + EWOULDBLOCK = EAGAIN, /* Operation would block */ + EINPROGRESS = 36, /* Operation now in progress */ + EALREADY = 37, /* Operation already in progress */ + + /* ipc/network software -- argument errors */ + ENOTSOCK = 38, /* Socket operation on non-socket */ + EDESTADDRREQ = 39, /* Destination address required */ + EMSGSIZE = 40, /* Message too long */ + EPROTOTYPE = 41, /* Protocol wrong type for socket */ + ENOPROTOOPT = 42, /* Protocol option not available */ + EPROTONOSUPPORT = 43, /* Protocol not supported */ + ESOCKTNOSUPPORT = 44, /* Socket type not supported */ + EOPNOTSUPP = 45, /* Operation not supported */ + EPFNOSUPPORT = 46, /* Protocol family not supported */ + EAFNOSUPPORT = 47, /* Address family not supported by protocol family */ + EADDRINUSE = 48, /* Address already in use */ + EADDRNOTAVAIL = 49, /* Can't assign requested address */ + + /* ipc/network software -- operational errors */ + ENETDOWN = 50, /* Network is down */ + ENETUNREACH = 51, /* Network is unreachable */ + ENETRESET = 52, /* Network dropped connection on reset */ + ECONNABORTED = 53, /* Software caused connection abort */ + ECONNRESET = 54, /* Connection reset by peer */ + ENOBUFS = 55, /* No buffer space available */ + EISCONN = 56, /* Socket is already connected */ + ENOTCONN = 57, /* Socket is not connected */ + ESHUTDOWN = 58, /* Can't send after socket shutdown */ + ETOOMANYREFS = 59, /* Too many references: can't splice */ + ETIMEDOUT = 60, /* Operation timed out */ + ECONNREFUSED = 61, /* Connection refused */ + + ELOOP = 62, /* Too many levels of symbolic links */ + ENAMETOOLONG = 63, /* File name too long */ + + /* should be rearranged */ + EHOSTDOWN = 64, /* Host is down */ + EHOSTUNREACH = 65, /* No route to host */ + ENOTEMPTY = 66, /* Directory not empty */ + + /* quotas & mush */ + EPROCLIM = 67, /* Too many processes */ + EUSERS = 68, /* Too many users */ + EDQUOT = 69, /* Disc quota exceeded */ + + /* Network File System */ + ESTALE = 70, /* Stale NFS file handle */ + EREMOTE = 71, /* Too many levels of remote in path */ + EBADRPC = 72, /* RPC struct is bad */ + ERPCMISMATCH = 73, /* RPC version wrong */ + EPROGUNAVAIL = 74, /* RPC prog. not avail */ + EPROGMISMATCH = 75, /* Program version wrong */ + EPROCUNAVAIL = 76, /* Bad procedure for program */ + + ENOLCK = 77, /* No locks available */ + ENOSYS = 78, /* Function not implemented */ + + EFTYPE = 79, /* Inappropriate file type or format */ + EAUTH = 80, /* Authentication error */ + ENEEDAUTH = 81, /* Need authenticator */ + + /* SystemV IPC */ + EIDRM = 82, /* Identifier removed */ + ENOMSG = 83, /* No message of desired type */ + EOVERFLOW = 84, /* Value too large to be stored in data type */ + + /* Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995 */ + EILSEQ = 85, /* Illegal byte sequence */ + + /* From IEEE Std 1003.1-2001 */ + /* Base, Realtime, Threads or Thread Priority Scheduling option errors */ + ENOTSUP = 86, /* Not supported */ + + /* Realtime option errors */ + ECANCELED = 87, /* Operation canceled */ + + /* Realtime, XSI STREAMS option errors */ + EBADMSG = 88, /* Bad or Corrupt message */ + + /* XSI STREAMS option errors */ + ENODATA = 89, /* No message available */ + ENOSR = 90, /* No STREAM resources */ + ENOSTR = 91, /* Not a STREAM */ + ETIME = 92, /* STREAM ioctl timeout */ + + /* File system extended attribute errors */ + ENOATTR = 93, /* Attribute not found */ + + /* Realtime, XSI STREAMS option errors */ + EMULTIHOP = 94, /* Multihop attempted */ + ENOLINK = 95, /* Link has been severed */ + EPROTO = 96, /* Protocol error */ + + /* Robust mutexes */ + EOWNERDEAD = 97, /* Previous owner died */ + ENOTRECOVERABLE = 98, /* State not recoverable */ + + ELAST = 98, /* Must equal largest errno */ +} + +EPERM :: Platform_Error.EPERM /* Operation not permitted */ +ENOENT :: Platform_Error.ENOENT /* No such file or directory */ +EINTR :: Platform_Error.EINTR /* Interrupted system call */ +ESRCH :: Platform_Error.ESRCH /* No such process */ +EIO :: Platform_Error.EIO /* Input/output error */ +ENXIO :: Platform_Error.ENXIO /* Device not configured */ +E2BIG :: Platform_Error.E2BIG /* Argument list too long */ +ENOEXEC :: Platform_Error.ENOEXEC /* Exec format error */ +EBADF :: Platform_Error.EBADF /* Bad file descriptor */ +ECHILD :: Platform_Error.ECHILD /* No child processes */ +EDEADLK :: Platform_Error.EDEADLK /* Resource deadlock avoided. 11 was EAGAIN */ +ENOMEM :: Platform_Error.ENOMEM /* Cannot allocate memory */ +EACCES :: Platform_Error.EACCES /* Permission denied */ +EFAULT :: Platform_Error.EFAULT /* Bad address */ +ENOTBLK :: Platform_Error.ENOTBLK /* Block device required */ +EBUSY :: Platform_Error.EBUSY /* Device busy */ +EEXIST :: Platform_Error.EEXIST /* File exists */ +EXDEV :: Platform_Error.EXDEV /* Cross-device link */ +ENODEV :: Platform_Error.ENODEV /* Operation not supported by device */ +ENOTDIR :: Platform_Error.ENOTDIR /* Not a directory */ +EISDIR :: Platform_Error.EISDIR /* Is a directory */ +EINVAL :: Platform_Error.EINVAL /* Invalid argument */ +ENFILE :: Platform_Error.ENFILE /* Too many open files in system */ +EMFILE :: Platform_Error.EMFILE /* Too many open files */ +ENOTTY :: Platform_Error.ENOTTY /* Inappropriate ioctl for device */ +ETXTBSY :: Platform_Error.ETXTBSY /* Text file busy */ +EFBIG :: Platform_Error.EFBIG /* File too large */ +ENOSPC :: Platform_Error.ENOSPC /* No space left on device */ +ESPIPE :: Platform_Error.ESPIPE /* Illegal seek */ +EROFS :: Platform_Error.EROFS /* Read-only file system */ +EMLINK :: Platform_Error.EMLINK /* Too many links */ +EPIPE :: Platform_Error.EPIPE /* Broken pipe */ /* math software */ -EDOM: Errno : 33 /* Numerical argument out of domain */ -ERANGE: Errno : 34 /* Result too large or too small */ +EDOM :: Platform_Error.EDOM /* Numerical argument out of domain */ +ERANGE :: Platform_Error.ERANGE /* Result too large or too small */ /* non-blocking and interrupt i/o */ -EAGAIN: Errno : 35 /* Resource temporarily unavailable */ -EWOULDBLOCK: Errno : EAGAIN /* Operation would block */ -EINPROGRESS: Errno : 36 /* Operation now in progress */ -EALREADY: Errno : 37 /* Operation already in progress */ +EAGAIN :: Platform_Error.EAGAIN /* Resource temporarily unavailable */ +EWOULDBLOCK :: EAGAIN /* Operation would block */ +EINPROGRESS :: Platform_Error.EINPROGRESS /* Operation now in progress */ +EALREADY :: Platform_Error.EALREADY /* Operation already in progress */ /* ipc/network software -- argument errors */ -ENOTSOCK: Errno : 38 /* Socket operation on non-socket */ -EDESTADDRREQ: Errno : 39 /* Destination address required */ -EMSGSIZE: Errno : 40 /* Message too long */ -EPROTOTYPE: Errno : 41 /* Protocol wrong type for socket */ -ENOPROTOOPT: Errno : 42 /* Protocol option not available */ -EPROTONOSUPPORT: Errno : 43 /* Protocol not supported */ -ESOCKTNOSUPPORT: Errno : 44 /* Socket type not supported */ -EOPNOTSUPP: Errno : 45 /* Operation not supported */ -EPFNOSUPPORT: Errno : 46 /* Protocol family not supported */ -EAFNOSUPPORT: Errno : 47 /* Address family not supported by protocol family */ -EADDRINUSE: Errno : 48 /* Address already in use */ -EADDRNOTAVAIL: Errno : 49 /* Can't assign requested address */ +ENOTSOCK :: Platform_Error.ENOTSOCK /* Socket operation on non-socket */ +EDESTADDRREQ :: Platform_Error.EDESTADDRREQ /* Destination address required */ +EMSGSIZE :: Platform_Error.EMSGSIZE /* Message too long */ +EPROTOTYPE :: Platform_Error.EPROTOTYPE /* Protocol wrong type for socket */ +ENOPROTOOPT :: Platform_Error.ENOPROTOOPT /* Protocol option not available */ +EPROTONOSUPPORT :: Platform_Error.EPROTONOSUPPORT /* Protocol not supported */ +ESOCKTNOSUPPORT :: Platform_Error.ESOCKTNOSUPPORT /* Socket type not supported */ +EOPNOTSUPP :: Platform_Error.EOPNOTSUPP /* Operation not supported */ +EPFNOSUPPORT :: Platform_Error.EPFNOSUPPORT /* Protocol family not supported */ +EAFNOSUPPORT :: Platform_Error.EAFNOSUPPORT /* Address family not supported by protocol family */ +EADDRINUSE :: Platform_Error.EADDRINUSE /* Address already in use */ +EADDRNOTAVAIL :: Platform_Error.EADDRNOTAVAIL /* Can't assign requested address */ /* ipc/network software -- operational errors */ -ENETDOWN: Errno : 50 /* Network is down */ -ENETUNREACH: Errno : 51 /* Network is unreachable */ -ENETRESET: Errno : 52 /* Network dropped connection on reset */ -ECONNABORTED: Errno : 53 /* Software caused connection abort */ -ECONNRESET: Errno : 54 /* Connection reset by peer */ -ENOBUFS: Errno : 55 /* No buffer space available */ -EISCONN: Errno : 56 /* Socket is already connected */ -ENOTCONN: Errno : 57 /* Socket is not connected */ -ESHUTDOWN: Errno : 58 /* Can't send after socket shutdown */ -ETOOMANYREFS: Errno : 59 /* Too many references: can't splice */ -ETIMEDOUT: Errno : 60 /* Operation timed out */ -ECONNREFUSED: Errno : 61 /* Connection refused */ - -ELOOP: Errno : 62 /* Too many levels of symbolic links */ -ENAMETOOLONG: Errno : 63 /* File name too long */ +ENETDOWN :: Platform_Error.ENETDOWN /* Network is down */ +ENETUNREACH :: Platform_Error.ENETUNREACH /* Network is unreachable */ +ENETRESET :: Platform_Error.ENETRESET /* Network dropped connection on reset */ +ECONNABORTED :: Platform_Error.ECONNABORTED /* Software caused connection abort */ +ECONNRESET :: Platform_Error.ECONNRESET /* Connection reset by peer */ +ENOBUFS :: Platform_Error.ENOBUFS /* No buffer space available */ +EISCONN :: Platform_Error.EISCONN /* Socket is already connected */ +ENOTCONN :: Platform_Error.ENOTCONN /* Socket is not connected */ +ESHUTDOWN :: Platform_Error.ESHUTDOWN /* Can't send after socket shutdown */ +ETOOMANYREFS :: Platform_Error.ETOOMANYREFS /* Too many references: can't splice */ +ETIMEDOUT :: Platform_Error.ETIMEDOUT /* Operation timed out */ +ECONNREFUSED :: Platform_Error.ECONNREFUSED /* Connection refused */ + +ELOOP :: Platform_Error.ELOOP /* Too many levels of symbolic links */ +ENAMETOOLONG :: Platform_Error.ENAMETOOLONG /* File name too long */ /* should be rearranged */ -EHOSTDOWN: Errno : 64 /* Host is down */ -EHOSTUNREACH: Errno : 65 /* No route to host */ -ENOTEMPTY: Errno : 66 /* Directory not empty */ +EHOSTDOWN :: Platform_Error.EHOSTDOWN /* Host is down */ +EHOSTUNREACH :: Platform_Error.EHOSTUNREACH /* No route to host */ +ENOTEMPTY :: Platform_Error.ENOTEMPTY /* Directory not empty */ /* quotas & mush */ -EPROCLIM: Errno : 67 /* Too many processes */ -EUSERS: Errno : 68 /* Too many users */ -EDQUOT: Errno : 69 /* Disc quota exceeded */ +EPROCLIM :: Platform_Error.EPROCLIM /* Too many processes */ +EUSERS :: Platform_Error.EUSERS /* Too many users */ +EDQUOT :: Platform_Error.EDQUOT /* Disc quota exceeded */ /* Network File System */ -ESTALE: Errno : 70 /* Stale NFS file handle */ -EREMOTE: Errno : 71 /* Too many levels of remote in path */ -EBADRPC: Errno : 72 /* RPC struct is bad */ -ERPCMISMATCH: Errno : 73 /* RPC version wrong */ -EPROGUNAVAIL: Errno : 74 /* RPC prog. not avail */ -EPROGMISMATCH: Errno : 75 /* Program version wrong */ -EPROCUNAVAIL: Errno : 76 /* Bad procedure for program */ +ESTALE :: Platform_Error.ESTALE /* Stale NFS file handle */ +EREMOTE :: Platform_Error.EREMOTE /* Too many levels of remote in path */ +EBADRPC :: Platform_Error.EBADRPC /* RPC struct is bad */ +ERPCMISMATCH :: Platform_Error.ERPCMISMATCH /* RPC version wrong */ +EPROGUNAVAIL :: Platform_Error.EPROGUNAVAIL /* RPC prog. not avail */ +EPROGMISMATCH :: Platform_Error.EPROGMISMATCH /* Program version wrong */ +EPROCUNAVAIL :: Platform_Error.EPROCUNAVAIL /* Bad procedure for program */ -ENOLCK: Errno : 77 /* No locks available */ -ENOSYS: Errno : 78 /* Function not implemented */ +ENOLCK :: Platform_Error.ENOLCK /* No locks available */ +ENOSYS :: Platform_Error.ENOSYS /* Function not implemented */ -EFTYPE: Errno : 79 /* Inappropriate file type or format */ -EAUTH: Errno : 80 /* Authentication error */ -ENEEDAUTH: Errno : 81 /* Need authenticator */ +EFTYPE :: Platform_Error.EFTYPE /* Inappropriate file type or format */ +EAUTH :: Platform_Error.EAUTH /* Authentication error */ +ENEEDAUTH :: Platform_Error.ENEEDAUTH /* Need authenticator */ /* SystemV IPC */ -EIDRM: Errno : 82 /* Identifier removed */ -ENOMSG: Errno : 83 /* No message of desired type */ -EOVERFLOW: Errno : 84 /* Value too large to be stored in data type */ +EIDRM :: Platform_Error.EIDRM /* Identifier removed */ +ENOMSG :: Platform_Error.ENOMSG /* No message of desired type */ +EOVERFLOW :: Platform_Error.EOVERFLOW /* Value too large to be stored in data type */ /* Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995 */ -EILSEQ: Errno : 85 /* Illegal byte sequence */ +EILSEQ :: Platform_Error.EILSEQ /* Illegal byte sequence */ /* From IEEE Std 1003.1-2001 */ /* Base, Realtime, Threads or Thread Priority Scheduling option errors */ -ENOTSUP: Errno : 86 /* Not supported */ +ENOTSUP :: Platform_Error.ENOTSUP /* Not supported */ /* Realtime option errors */ -ECANCELED: Errno : 87 /* Operation canceled */ +ECANCELED :: Platform_Error.ECANCELED /* Operation canceled */ /* Realtime, XSI STREAMS option errors */ -EBADMSG: Errno : 88 /* Bad or Corrupt message */ +EBADMSG :: Platform_Error.EBADMSG /* Bad or Corrupt message */ /* XSI STREAMS option errors */ -ENODATA: Errno : 89 /* No message available */ -ENOSR: Errno : 90 /* No STREAM resources */ -ENOSTR: Errno : 91 /* Not a STREAM */ -ETIME: Errno : 92 /* STREAM ioctl timeout */ +ENODATA :: Platform_Error.ENODATA /* No message available */ +ENOSR :: Platform_Error.ENOSR /* No STREAM resources */ +ENOSTR :: Platform_Error.ENOSTR /* Not a STREAM */ +ETIME :: Platform_Error.ETIME /* STREAM ioctl timeout */ /* File system extended attribute errors */ -ENOATTR: Errno : 93 /* Attribute not found */ +ENOATTR :: Platform_Error.ENOATTR /* Attribute not found */ /* Realtime, XSI STREAMS option errors */ -EMULTIHOP: Errno : 94 /* Multihop attempted */ -ENOLINK: Errno : 95 /* Link has been severed */ -EPROTO: Errno : 96 /* Protocol error */ +EMULTIHOP :: Platform_Error.EMULTIHOP /* Multihop attempted */ +ENOLINK :: Platform_Error.ENOLINK /* Link has been severed */ +EPROTO :: Platform_Error.EPROTO /* Protocol error */ /* Robust mutexes */ -EOWNERDEAD: Errno : 97 /* Previous owner died */ -ENOTRECOVERABLE: Errno : 98 /* State not recoverable */ +EOWNERDEAD :: Platform_Error.EOWNERDEAD /* Previous owner died */ +ENOTRECOVERABLE :: Platform_Error.ENOTRECOVERABLE /* State not recoverable */ -ELAST: Errno : 98 /* Must equal largest errno */ +ELAST :: Platform_Error.ELAST /* Must equal largest errno */ /* end of errno */ @@ -338,8 +477,8 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } -get_last_error :: proc "contextless" () -> int { - return int(__errno_location()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__errno_location()^) } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index a3b74a524..cc7642387 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -9,108 +9,205 @@ import "base:runtime" Handle :: distinct i32 Pid :: distinct i32 File_Time :: distinct u64 -Errno :: distinct i32 INVALID_HANDLE :: ~Handle(0) -ERROR_NONE: Errno: 0 - -EPERM: Errno: 1 -ENOENT: Errno: 2 -ESRCH: Errno: 3 -EINTR: Errno: 4 -EIO: Errno: 5 -ENXIO: Errno: 6 -E2BIG: Errno: 7 -ENOEXEC: Errno: 8 -EBADF: Errno: 9 -ECHILD: Errno: 10 -EDEADLK: Errno: 11 -ENOMEM: Errno: 12 -EACCES: Errno: 13 -EFAULT: Errno: 14 -ENOTBLK: Errno: 15 -EBUSY: Errno: 16 -EEXIST: Errno: 17 -EXDEV: Errno: 18 -ENODEV: Errno: 19 -ENOTDIR: Errno: 20 -EISDIR: Errno: 21 -EINVAL: Errno: 22 -ENFILE: Errno: 23 -EMFILE: Errno: 24 -ENOTTY: Errno: 25 -ETXTBSY: Errno: 26 -EFBIG: Errno: 27 -ENOSPC: Errno: 28 -ESPIPE: Errno: 29 -EROFS: Errno: 30 -EMLINK: Errno: 31 -EPIPE: Errno: 32 -EDOM: Errno: 33 -ERANGE: Errno: 34 -EAGAIN: Errno: 35 -EWOULDBLOCK: Errno: EAGAIN -EINPROGRESS: Errno: 36 -EALREADY: Errno: 37 -ENOTSOCK: Errno: 38 -EDESTADDRREQ: Errno: 39 -EMSGSIZE: Errno: 40 -EPROTOTYPE: Errno: 41 -ENOPROTOOPT: Errno: 42 -EPROTONOSUPPORT: Errno: 43 -ESOCKTNOSUPPORT: Errno: 44 -EOPNOTSUPP: Errno: 45 -EPFNOSUPPORT: Errno: 46 -EAFNOSUPPORT: Errno: 47 -EADDRINUSE: Errno: 48 -EADDRNOTAVAIL: Errno: 49 -ENETDOWN: Errno: 50 -ENETUNREACH: Errno: 51 -ENETRESET: Errno: 52 -ECONNABORTED: Errno: 53 -ECONNRESET: Errno: 54 -ENOBUFS: Errno: 55 -EISCONN: Errno: 56 -ENOTCONN: Errno: 57 -ESHUTDOWN: Errno: 58 -ETOOMANYREFS: Errno: 59 -ETIMEDOUT: Errno: 60 -ECONNREFUSED: Errno: 61 -ELOOP: Errno: 62 -ENAMETOOLONG: Errno: 63 -EHOSTDOWN: Errno: 64 -EHOSTUNREACH: Errno: 65 -ENOTEMPTY: Errno: 66 -EPROCLIM: Errno: 67 -EUSERS: Errno: 68 -EDQUOT: Errno: 69 -ESTALE: Errno: 70 -EREMOTE: Errno: 71 -EBADRPC: Errno: 72 -ERPCMISMATCH: Errno: 73 -EPROGUNAVAIL: Errno: 74 -EPROGMISMATCH: Errno: 75 -EPROCUNAVAIL: Errno: 76 -ENOLCK: Errno: 77 -ENOSYS: Errno: 78 -EFTYPE: Errno: 79 -EAUTH: Errno: 80 -ENEEDAUTH: Errno: 81 -EIPSEC: Errno: 82 -ENOATTR: Errno: 83 -EILSEQ: Errno: 84 -ENOMEDIUM: Errno: 85 -EMEDIUMTYPE: Errno: 86 -EOVERFLOW: Errno: 87 -ECANCELED: Errno: 88 -EIDRM: Errno: 89 -ENOMSG: Errno: 90 -ENOTSUP: Errno: 91 -EBADMSG: Errno: 92 -ENOTRECOVERABLE: Errno: 93 -EOWNERDEAD: Errno: 94 -EPROTO: Errno: 95 +_Platform_Error :: enum i32 { + NONE = 0, + 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, + ENOTBLK = 15, + 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, + EDOM = 33, + ERANGE = 34, + EAGAIN = 35, + EWOULDBLOCK = EAGAIN, + EINPROGRESS = 36, + EALREADY = 37, + ENOTSOCK = 38, + EDESTADDRREQ = 39, + EMSGSIZE = 40, + EPROTOTYPE = 41, + ENOPROTOOPT = 42, + EPROTONOSUPPORT = 43, + ESOCKTNOSUPPORT = 44, + EOPNOTSUPP = 45, + EPFNOSUPPORT = 46, + EAFNOSUPPORT = 47, + EADDRINUSE = 48, + EADDRNOTAVAIL = 49, + ENETDOWN = 50, + ENETUNREACH = 51, + ENETRESET = 52, + ECONNABORTED = 53, + ECONNRESET = 54, + ENOBUFS = 55, + EISCONN = 56, + ENOTCONN = 57, + ESHUTDOWN = 58, + ETOOMANYREFS = 59, + ETIMEDOUT = 60, + ECONNREFUSED = 61, + ELOOP = 62, + ENAMETOOLONG = 63, + EHOSTDOWN = 64, + EHOSTUNREACH = 65, + ENOTEMPTY = 66, + EPROCLIM = 67, + EUSERS = 68, + EDQUOT = 69, + ESTALE = 70, + EREMOTE = 71, + EBADRPC = 72, + ERPCMISMATCH = 73, + EPROGUNAVAIL = 74, + EPROGMISMATCH = 75, + EPROCUNAVAIL = 76, + ENOLCK = 77, + ENOSYS = 78, + EFTYPE = 79, + EAUTH = 80, + ENEEDAUTH = 81, + EIPSEC = 82, + ENOATTR = 83, + EILSEQ = 84, + ENOMEDIUM = 85, + EMEDIUMTYPE = 86, + EOVERFLOW = 87, + ECANCELED = 88, + EIDRM = 89, + ENOMSG = 90, + ENOTSUP = 91, + EBADMSG = 92, + ENOTRECOVERABLE = 93, + EOWNERDEAD = 94, + EPROTO = 95, +} + +EPERM :: Platform_Error.EPERM +ENOENT :: Platform_Error.ENOENT +ESRCH :: Platform_Error.ESRCH +EINTR :: Platform_Error.EINTR +EIO :: Platform_Error.EIO +ENXIO :: Platform_Error.ENXIO +E2BIG :: Platform_Error.E2BIG +ENOEXEC :: Platform_Error.ENOEXEC +EBADF :: Platform_Error.EBADF +ECHILD :: Platform_Error.ECHILD +EDEADLK :: Platform_Error.EDEADLK +ENOMEM :: Platform_Error.ENOMEM +EACCES :: Platform_Error.EACCES +EFAULT :: Platform_Error.EFAULT +ENOTBLK :: Platform_Error.ENOTBLK +EBUSY :: Platform_Error.EBUSY +EEXIST :: Platform_Error.EEXIST +EXDEV :: Platform_Error.EXDEV +ENODEV :: Platform_Error.ENODEV +ENOTDIR :: Platform_Error.ENOTDIR +EISDIR :: Platform_Error.EISDIR +EINVAL :: Platform_Error.EINVAL +ENFILE :: Platform_Error.ENFILE +EMFILE :: Platform_Error.EMFILE +ENOTTY :: Platform_Error.ENOTTY +ETXTBSY :: Platform_Error.ETXTBSY +EFBIG :: Platform_Error.EFBIG +ENOSPC :: Platform_Error.ENOSPC +ESPIPE :: Platform_Error.ESPIPE +EROFS :: Platform_Error.EROFS +EMLINK :: Platform_Error.EMLINK +EPIPE :: Platform_Error.EPIPE +EDOM :: Platform_Error.EDOM +ERANGE :: Platform_Error.ERANGE +EAGAIN :: Platform_Error.EAGAIN +EWOULDBLOCK :: Platform_Error.EWOULDBLOCK +EINPROGRESS :: Platform_Error.EINPROGRESS +EALREADY :: Platform_Error.EALREADY +ENOTSOCK :: Platform_Error.ENOTSOCK +EDESTADDRREQ :: Platform_Error.EDESTADDRREQ +EMSGSIZE :: Platform_Error.EMSGSIZE +EPROTOTYPE :: Platform_Error.EPROTOTYPE +ENOPROTOOPT :: Platform_Error.ENOPROTOOPT +EPROTONOSUPPORT :: Platform_Error.EPROTONOSUPPORT +ESOCKTNOSUPPORT :: Platform_Error.ESOCKTNOSUPPORT +EOPNOTSUPP :: Platform_Error.EOPNOTSUPP +EPFNOSUPPORT :: Platform_Error.EPFNOSUPPORT +EAFNOSUPPORT :: Platform_Error.EAFNOSUPPORT +EADDRINUSE :: Platform_Error.EADDRINUSE +EADDRNOTAVAIL :: Platform_Error.EADDRNOTAVAIL +ENETDOWN :: Platform_Error.ENETDOWN +ENETUNREACH :: Platform_Error.ENETUNREACH +ENETRESET :: Platform_Error.ENETRESET +ECONNABORTED :: Platform_Error.ECONNABORTED +ECONNRESET :: Platform_Error.ECONNRESET +ENOBUFS :: Platform_Error.ENOBUFS +EISCONN :: Platform_Error.EISCONN +ENOTCONN :: Platform_Error.ENOTCONN +ESHUTDOWN :: Platform_Error.ESHUTDOWN +ETOOMANYREFS :: Platform_Error.ETOOMANYREFS +ETIMEDOUT :: Platform_Error.ETIMEDOUT +ECONNREFUSED :: Platform_Error.ECONNREFUSED +ELOOP :: Platform_Error.ELOOP +ENAMETOOLONG :: Platform_Error.ENAMETOOLONG +EHOSTDOWN :: Platform_Error.EHOSTDOWN +EHOSTUNREACH :: Platform_Error.EHOSTUNREACH +ENOTEMPTY :: Platform_Error.ENOTEMPTY +EPROCLIM :: Platform_Error.EPROCLIM +EUSERS :: Platform_Error.EUSERS +EDQUOT :: Platform_Error.EDQUOT +ESTALE :: Platform_Error.ESTALE +EREMOTE :: Platform_Error.EREMOTE +EBADRPC :: Platform_Error.EBADRPC +ERPCMISMATCH :: Platform_Error.ERPCMISMATCH +EPROGUNAVAIL :: Platform_Error.EPROGUNAVAIL +EPROGMISMATCH :: Platform_Error.EPROGMISMATCH +EPROCUNAVAIL :: Platform_Error.EPROCUNAVAIL +ENOLCK :: Platform_Error.ENOLCK +ENOSYS :: Platform_Error.ENOSYS +EFTYPE :: Platform_Error.EFTYPE +EAUTH :: Platform_Error.EAUTH +ENEEDAUTH :: Platform_Error.ENEEDAUTH +EIPSEC :: Platform_Error.EIPSEC +ENOATTR :: Platform_Error.ENOATTR +EILSEQ :: Platform_Error.EILSEQ +ENOMEDIUM :: Platform_Error.ENOMEDIUM +EMEDIUMTYPE :: Platform_Error.EMEDIUMTYPE +EOVERFLOW :: Platform_Error.EOVERFLOW +ECANCELED :: Platform_Error.ECANCELED +EIDRM :: Platform_Error.EIDRM +ENOMSG :: Platform_Error.ENOMSG +ENOTSUP :: Platform_Error.ENOTSUP +EBADMSG :: Platform_Error.EBADMSG +ENOTRECOVERABLE :: Platform_Error.ENOTRECOVERABLE +EOWNERDEAD :: Platform_Error.EOWNERDEAD +EPROTO :: Platform_Error.EPROTO O_RDONLY :: 0x00000 O_WRONLY :: 0x00001 @@ -295,8 +392,8 @@ is_path_separator :: proc(r: rune) -> bool { return r == '/' } -get_last_error :: proc "contextless" () -> int { - return int(__error()^) +get_last_error :: proc "contextless" () -> Error { + return Error(__error()^) } fork :: proc() -> (Pid, Errno) { diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 7b7fb4686..36db0f622 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -4,11 +4,13 @@ import "core:sys/wasm/wasi" import "base:runtime" Handle :: distinct i32 -Errno :: distinct i32 +_Platform_Error :: enum i32 { + NONE = 0, +} INVALID_HANDLE :: -1 -ERROR_NONE :: Errno(wasi.errno_t.SUCCESS) +// ERROR_NONE :: Errno(wasi.errno_t.SUCCESS) // that is a weird error code. Probably better to remap it O_RDONLY :: 0x00000 O_WRONLY :: 0x00001 diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index ecfb0b419..0ec0b6091 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -7,7 +7,6 @@ import "base:intrinsics" Handle :: distinct uintptr File_Time :: distinct u64 -Errno :: distinct int INVALID_HANDLE :: ~Handle(0) @@ -27,38 +26,38 @@ O_SYNC :: 0x01000 O_ASYNC :: 0x02000 O_CLOEXEC :: 0x80000 - -ERROR_NONE: Errno : 0 -ERROR_FILE_NOT_FOUND: Errno : 2 -ERROR_PATH_NOT_FOUND: Errno : 3 -ERROR_ACCESS_DENIED: Errno : 5 -ERROR_INVALID_HANDLE: Errno : 6 -ERROR_NOT_ENOUGH_MEMORY: Errno : 8 -ERROR_NO_MORE_FILES: Errno : 18 -ERROR_HANDLE_EOF: Errno : 38 -ERROR_NETNAME_DELETED: Errno : 64 -ERROR_FILE_EXISTS: Errno : 80 -ERROR_INVALID_PARAMETER: Errno : 87 -ERROR_BROKEN_PIPE: Errno : 109 -ERROR_BUFFER_OVERFLOW: Errno : 111 -ERROR_INSUFFICIENT_BUFFER: Errno : 122 -ERROR_MOD_NOT_FOUND: Errno : 126 -ERROR_PROC_NOT_FOUND: Errno : 127 -ERROR_DIR_NOT_EMPTY: Errno : 145 -ERROR_ALREADY_EXISTS: Errno : 183 -ERROR_ENVVAR_NOT_FOUND: Errno : 203 -ERROR_MORE_DATA: Errno : 234 -ERROR_OPERATION_ABORTED: Errno : 995 -ERROR_IO_PENDING: Errno : 997 -ERROR_NOT_FOUND: Errno : 1168 -ERROR_PRIVILEGE_NOT_HELD: Errno : 1314 -WSAEACCES: Errno : 10013 -WSAECONNRESET: Errno : 10054 +_Platform_Error :: win32.System_Error + +ERROR_FILE_NOT_FOUND :: _Platform_Error(2) +ERROR_PATH_NOT_FOUND :: _Platform_Error(3) +ERROR_ACCESS_DENIED :: _Platform_Error(5) +ERROR_INVALID_HANDLE :: _Platform_Error(6) +ERROR_NOT_ENOUGH_MEMORY :: _Platform_Error(8) +ERROR_NO_MORE_FILES :: _Platform_Error(18) +ERROR_HANDLE_EOF :: _Platform_Error(38) +ERROR_NETNAME_DELETED :: _Platform_Error(64) +ERROR_FILE_EXISTS :: _Platform_Error(80) +ERROR_INVALID_PARAMETER :: _Platform_Error(87) +ERROR_BROKEN_PIPE :: _Platform_Error(109) +ERROR_BUFFER_OVERFLOW :: _Platform_Error(111) +ERROR_INSUFFICIENT_BUFFER :: _Platform_Error(122) +ERROR_MOD_NOT_FOUND :: _Platform_Error(126) +ERROR_PROC_NOT_FOUND :: _Platform_Error(127) +ERROR_DIR_NOT_EMPTY :: _Platform_Error(145) +ERROR_ALREADY_EXISTS :: _Platform_Error(183) +ERROR_ENVVAR_NOT_FOUND :: _Platform_Error(203) +ERROR_MORE_DATA :: _Platform_Error(234) +ERROR_OPERATION_ABORTED :: _Platform_Error(995) +ERROR_IO_PENDING :: _Platform_Error(997) +ERROR_NOT_FOUND :: _Platform_Error(1168) +ERROR_PRIVILEGE_NOT_HELD :: _Platform_Error(1314) +WSAEACCES :: _Platform_Error(10013) +WSAECONNRESET :: _Platform_Error(10054) // Windows reserves errors >= 1<<29 for application use -ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0 -ERROR_FILE_IS_NOT_DIR: Errno : 1<<29 + 1 -ERROR_NEGATIVE_OFFSET: Errno : 1<<29 + 2 +ERROR_FILE_IS_PIPE :: _Platform_Error(1<<29 + 0) +ERROR_FILE_IS_NOT_DIR :: _Platform_Error(1<<29 + 1) +ERROR_NEGATIVE_OFFSET :: _Platform_Error(1<<29 + 2) // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() diff --git a/core/prof/spall/spall_unix.odin b/core/prof/spall/spall_unix.odin index e6199d86b..e6ba7ecde 100644 --- a/core/prof/spall/spall_unix.odin +++ b/core/prof/spall/spall_unix.odin @@ -23,8 +23,8 @@ foreign libc { } @(no_instrumentation) -get_last_error :: proc "contextless" () -> int { - return int(__error()^) +get_last_error :: proc "contextless" () -> os.Platform_Error { + return os.Platform_Error(__error()^) } MAX_RW :: 0x7fffffff diff --git a/core/sync/futex_haiku.odin b/core/sync/futex_haiku.odin index b81743cad..6fe5894a0 100644 --- a/core/sync/futex_haiku.odin +++ b/core/sync/futex_haiku.odin @@ -2,7 +2,6 @@ package sync import "core:c" -import "base:runtime" import "core:sys/haiku" import "core:sys/unix" import "core:time" @@ -86,10 +85,10 @@ _futex_wait :: proc "contextless" (f: ^Futex, expect: u32) -> (ok: bool) { waiter.prev.next = waiter.next waiter.next.prev = waiter.prev - unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil) + _ = unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil) // FIXME: Add error handling! - return + return } _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration: time.Duration) -> (ok: bool) { @@ -133,10 +132,10 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration waiter.prev.next = waiter.next waiter.next.prev = waiter.prev - unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil) + unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil) - // FIXME: Add error handling! - return + // FIXME: Add error handling! + return } _futex_signal :: proc "contextless" (f: ^Futex) { diff --git a/core/sys/haiku/os.odin b/core/sys/haiku/os.odin index 1e00145eb..883072c2d 100644 --- a/core/sys/haiku/os.odin +++ b/core/sys/haiku/os.odin @@ -399,7 +399,7 @@ cpu_topology_node_info :: struct { }, _package: struct { vendor: cpu_vendor, - cache_line_size: u32 + cache_line_size: u32, }, _core: struct { model: u32, diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 01ff9da5b..78b88f21a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -127,6 +127,8 @@ gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finis gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y); +gb_internal bool is_exact_value_zero(ExactValue const &v); + enum LoadDirectiveResult { LoadDirective_Success = 0, LoadDirective_Error = 1, @@ -4364,6 +4366,25 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar } switch (t->kind) { + // IMPORTANT NOTE HACK(bill): This is just to allow for comparisons against `0` with the `os.Error` type + // as a kind of transition period + case Type_Enum: + if (operand->mode == Addressing_Constant && + target_type->kind == Type_Named && + target_type->Named.name == "Error") { + Entity *e = target_type->Named.type_name; + if (e->pkg && e->pkg->name == "os") { + if (is_exact_value_zero(operand->value)) { + check_is_expressible(c, operand, t); + if (operand->mode == Addressing_Invalid) { + return; + } + update_untyped_expr_value(c, operand->expr, operand->value); + } + } + } + break; + case Type_Basic: if (operand->mode == Addressing_Constant) { check_is_expressible(c, operand, t); -- cgit v1.2.3 From 9f9abb8fb30cb184771094b8cf44346147a6c2fc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:05:30 +0100 Subject: Use `union #shared_nil` for `os.Error` --- core/crypto/rand_windows.odin | 4 ++-- core/os/dir_windows.odin | 4 ++-- core/os/env_windows.odin | 4 ++-- core/os/file_windows.odin | 39 ++++++++++++++++++------------------ core/os/os.odin | 17 ++++++++++++---- core/os/os_darwin.odin | 10 ++++----- core/os/os_freebsd.odin | 2 +- core/os/os_haiku.odin | 2 +- core/os/os_linux.odin | 6 +++--- core/os/os_netbsd.odin | 2 +- core/os/os_openbsd.odin | 2 +- core/os/os_wasi.odin | 20 +++++++++--------- core/os/os_windows.odin | 10 +++++---- core/os/stat_windows.odin | 16 +++++++-------- core/path/filepath/path_windows.odin | 4 ++-- core/prof/spall/spall_windows.odin | 2 +- core/sys/wasm/wasi/wasi_api.odin | 1 + src/check_expr.cpp | 35 +++++++++++++++----------------- 18 files changed, 93 insertions(+), 87 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/core/crypto/rand_windows.odin b/core/crypto/rand_windows.odin index 6392cd51f..83a976e38 100644 --- a/core/crypto/rand_windows.odin +++ b/core/crypto/rand_windows.odin @@ -8,8 +8,8 @@ HAS_RAND_BYTES :: true @(private) _rand_bytes :: proc(dst: []byte) { - ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)) - if ret != os.ERROR_NONE { + ret := os.Platform_Error(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG)) + if ret != nil { #partial switch ret { case os.ERROR_INVALID_HANDLE: // The handle to the first parameter is invalid. diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index 9ca78948e..adf502708 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -88,7 +88,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F find_data := &win32.WIN32_FIND_DATAW{} find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data) if find_handle == win32.INVALID_HANDLE_VALUE { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) return dfi[:], err } defer win32.FindClose(find_handle) @@ -101,7 +101,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F } if !win32.FindNextFileW(find_handle, find_data) { - e := Errno(win32.GetLastError()) + e := Platform_Error(win32.GetLastError()) if e == ERROR_NO_MORE_FILES { break } diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin index 0e3c7f04a..7d26d5b4b 100644 --- a/core/os/env_windows.odin +++ b/core/os/env_windows.odin @@ -50,7 +50,7 @@ set_env :: proc(key, value: string) -> Errno { v := win32.utf8_to_wstring(value) if !win32.SetEnvironmentVariableW(k, v) { - return Errno(win32.GetLastError()) + return Platform_Error(win32.GetLastError()) } return 0 } @@ -59,7 +59,7 @@ set_env :: proc(key, value: string) -> Errno { unset_env :: proc(key: string) -> Errno { k := win32.utf8_to_wstring(key) if !win32.SetEnvironmentVariableW(k, nil) { - return Errno(win32.GetLastError()) + return Platform_Error(win32.GetLastError()) } return 0 } diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index d900c5e70..a00a49cba 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -55,20 +55,20 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn return handle, ERROR_NONE } - err := Errno(win32.GetLastError()) + err := Platform_Error(win32.GetLastError()) return INVALID_HANDLE, err } close :: proc(fd: Handle) -> Errno { if !win32.CloseHandle(win32.HANDLE(fd)) { - return Errno(win32.GetLastError()) + return Platform_Error(win32.GetLastError()) } return ERROR_NONE } flush :: proc(fd: Handle) -> (err: Errno) { if !win32.FlushFileBuffers(win32.HANDLE(fd)) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } @@ -90,7 +90,7 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil) if single_write_length <= 0 || !e { - err := Errno(win32.GetLastError()) + err := Platform_Error(win32.GetLastError()) return int(total_write), err } total_write += i64(single_write_length) @@ -118,7 +118,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) { single_read_length: u32 ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil) if !ok { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } buf8_len := utf16.decode_to_utf8(buf8[:], buf16[:single_read_length]) @@ -180,7 +180,7 @@ read :: proc(fd: Handle, data: []byte) -> (total_read: int, err: Errno) { return int(bytes_read), ERROR_NONE } } else { - return 0, Errno(win32.GetLastError()) + return 0, Platform_Error(win32.GetLastError()) } } return total_read, ERROR_NONE @@ -202,7 +202,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { dw_ptr := win32.SetFilePointer(win32.HANDLE(fd), lo, &hi, w) if dw_ptr == win32.INVALID_SET_FILE_POINTER { - err := Errno(win32.GetLastError()) + err := Platform_Error(win32.GetLastError()) return 0, err } return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE @@ -212,7 +212,7 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { length: win32.LARGE_INTEGER err: Errno if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return i64(length), err } @@ -220,7 +220,6 @@ file_size :: proc(fd: Handle) -> (i64, Errno) { @(private) MAX_RW :: 1<<30 -ERROR_EOF :: 38 @(private) pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { @@ -241,7 +240,7 @@ pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { done: win32.DWORD e: Errno if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) { - e = Errno(win32.GetLastError()) + e = Platform_Error(win32.GetLastError()) done = 0 } return int(done), e @@ -263,7 +262,7 @@ pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { done: win32.DWORD e: Errno if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) { - e = Errno(win32.GetLastError()) + e = Platform_Error(win32.GetLastError()) done = 0 } return int(done), e @@ -400,7 +399,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) { win32.AcquireSRWLockExclusive(&cwd_lock) if !win32.SetCurrentDirectoryW(wstr) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } win32.ReleaseSRWLockExclusive(&cwd_lock) @@ -415,7 +414,7 @@ make_directory :: proc(path: string, mode: u32 = 0) -> (err: Errno) { wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.CreateDirectoryW(wpath, nil) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } @@ -426,7 +425,7 @@ remove_directory :: proc(path: string) -> (err: Errno) { wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.RemoveDirectoryW(wpath) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } @@ -498,7 +497,7 @@ link :: proc(old_name, new_name: string) -> (err: Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() n := win32.utf8_to_wstring(fix_long_path(new_name)) o := win32.utf8_to_wstring(fix_long_path(old_name)) - return Errno(win32.CreateHardLinkW(n, o, nil)) + return Platform_Error(win32.CreateHardLinkW(n, o, nil)) } unlink :: proc(path: string) -> (err: Errno) { @@ -506,7 +505,7 @@ unlink :: proc(path: string) -> (err: Errno) { wpath := win32.utf8_to_wstring(path, context.temp_allocator) if !win32.DeleteFileW(wpath) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } @@ -519,7 +518,7 @@ rename :: proc(old_path, new_path: string) -> (err: Errno) { to := win32.utf8_to_wstring(new_path, context.temp_allocator) if !win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } @@ -537,7 +536,7 @@ ftruncate :: proc(fd: Handle, length: i64) -> (err: Errno) { } ok := win32.SetEndOfFile(win32.HANDLE(fd)) if !ok { - return Errno(win32.GetLastError()) + return Platform_Error(win32.GetLastError()) } return ERROR_NONE } @@ -588,7 +587,7 @@ remove :: proc(name: string) -> Errno { } } - return Errno(err) + return Platform_Error(err) } @@ -597,7 +596,7 @@ pipe :: proc() -> (r, w: Handle, err: Errno) { sa.nLength = size_of(win32.SECURITY_ATTRIBUTES) sa.bInheritHandle = true if !win32.CreatePipe((^win32.HANDLE)(&r), (^win32.HANDLE)(&w), &sa, 0) { - err = Errno(win32.GetLastError()) + err = Platform_Error(win32.GetLastError()) } return } diff --git a/core/os/os.odin b/core/os/os.odin index 3f48c59df..6f2cdb8e3 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -1,5 +1,6 @@ package os +import "base:intrinsics" import "base:runtime" import "core:strconv" import "core:unicode/utf8" @@ -14,10 +15,18 @@ SEEK_CUR :: 1 SEEK_END :: 2 Platform_Error :: _Platform_Error -Error :: Platform_Error -Errno :: Error // alias +#assert(size_of(Platform_Error) <= 4) +#assert(intrinsics.type_has_nil(Platform_Error)) -ERROR_NONE :: Errno(0) +Errno :: Error // alias for legacy use + +Error :: union #shared_nil { + Platform_Error, + runtime.Allocator_Error, +} +#assert(size_of(Error) <= 8) + +ERROR_NONE :: Error{} write_string :: proc(fd: Handle, str: string) -> (int, Errno) { return write(fd, transmute([]byte)str) @@ -67,7 +76,7 @@ write_encoded_rune :: proc(fd: Handle, r: rune) { read_at_least :: proc(fd: Handle, buf: []byte, min: int) -> (n: int, err: Errno) { if len(buf) < min { - return 0, -1 + return 0, Platform_Error(~intrinsics.type_core_type(Platform_Error)(0)) // TODO(bill): replace this error } nn := max(int) for nn > 0 && n < min && err == 0 { diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index f72529682..216620aa7 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -636,7 +636,7 @@ foreign dl { } get_last_error :: proc "contextless" () -> Error { - return Error(__error()^) + return Platform_Error(__error()^) } get_last_error_string :: proc() -> string { @@ -678,11 +678,11 @@ open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno } fchmod :: proc(fd: Handle, mode: u16) -> Errno { - return cast(Errno)_unix_fchmod(fd, mode) + return cast(Platform_Error)_unix_fchmod(fd, mode) } close :: proc(fd: Handle) -> Errno { - return cast(Errno)_unix_close(fd) + return cast(Platform_Error)_unix_close(fd) } // If you read or write more than `SSIZE_MAX` bytes, most darwin implementations will return `EINVAL` @@ -756,7 +756,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { final_offset := i64(_unix_lseek(fd, int(offset), c.int(whence))) if final_offset == -1 { - return 0, 1 + return 0, Platform_Error.EPERM } return final_offset, 0 } @@ -1011,7 +1011,7 @@ access :: proc(path: string, mask: int) -> bool { } flush :: proc(fd: Handle) -> Errno { - return cast(Errno)_unix_fsync(fd) + return cast(Platform_Error)_unix_fsync(fd) } lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 7090a7773..d9efe0902 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -420,7 +420,7 @@ is_path_separator :: proc(r: rune) -> bool { } get_last_error :: proc "contextless" () -> Error { - return Error(__errno_location()^) + return Platform_Error(__errno_location()^) } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index 03e2c5e64..784ae1135 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -182,7 +182,7 @@ is_path_separator :: proc(r: rune) -> bool { } get_last_error :: proc "contextless" () -> Error { - return Error(__error()^) + return Platform_Error(__error()^) } fork :: proc() -> (Pid, Errno) { diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index ace24d26a..bd55a229b 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -514,14 +514,14 @@ is_path_separator :: proc(r: rune) -> bool { @private _get_errno :: proc(res: int) -> Errno { if res < 0 && res > -4096 { - return Errno(-res) + return Platform_Error(-res) } - return 0 + return nil } // get errno from libc get_last_error :: proc "contextless" () -> Error { - return Error(__errno_location()^) + return Platform_Error(__errno_location()^) } personality :: proc(persona: u64) -> (Errno) { diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index b27daac3a..3de440542 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -478,7 +478,7 @@ is_path_separator :: proc(r: rune) -> bool { } get_last_error :: proc "contextless" () -> Error { - return Error(__errno_location()^) + return Platform_Error(__errno_location()^) } open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index cc7642387..f1ad9ab38 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -393,7 +393,7 @@ is_path_separator :: proc(r: rune) -> bool { } get_last_error :: proc "contextless" () -> Error { - return Error(__error()^) + return Platform_Error(__error()^) } fork :: proc() -> (Pid, Errno) { diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 36db0f622..f2c5b62b4 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -4,9 +4,7 @@ import "core:sys/wasm/wasi" import "base:runtime" Handle :: distinct i32 -_Platform_Error :: enum i32 { - NONE = 0, -} +_Platform_Error :: wasi.errno_t INVALID_HANDLE :: -1 @@ -150,22 +148,22 @@ wasi_match_preopen :: proc(path: string) -> (wasi.fd_t, string, bool) { write :: proc(fd: Handle, data: []byte) -> (int, Errno) { iovs := wasi.ciovec_t(data) n, err := wasi.fd_write(wasi.fd_t(fd), {iovs}) - return int(n), Errno(err) + return int(n), Platform_Error(err) } read :: proc(fd: Handle, data: []byte) -> (int, Errno) { iovs := wasi.iovec_t(data) n, err := wasi.fd_read(wasi.fd_t(fd), {iovs}) - return int(n), Errno(err) + return int(n), Platform_Error(err) } write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { iovs := wasi.ciovec_t(data) n, err := wasi.fd_pwrite(wasi.fd_t(fd), {iovs}, wasi.filesize_t(offset)) - return int(n), Errno(err) + return int(n), Platform_Error(err) } read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { iovs := wasi.iovec_t(data) n, err := wasi.fd_pread(wasi.fd_t(fd), {iovs}, wasi.filesize_t(offset)) - return int(n), Errno(err) + return int(n), Platform_Error(err) } open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errno) { oflags: wasi.oflags_t @@ -203,15 +201,15 @@ open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Errn } fd, err := wasi.path_open(dir_fd, {.SYMLINK_FOLLOW}, relative, oflags, rights, {}, fdflags) - return Handle(fd), Errno(err) + return Handle(fd), Platform_Error(err) } close :: proc(fd: Handle) -> Errno { err := wasi.fd_close(wasi.fd_t(fd)) - return Errno(err) + return Platform_Error(err) } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { n, err := wasi.fd_seek(wasi.fd_t(fd), wasi.filedelta_t(offset), wasi.whence_t(whence)) - return i64(n), Errno(err) + return i64(n), Platform_Error(err) } current_thread_id :: proc "contextless" () -> int { return 0 @@ -224,7 +222,7 @@ _processor_core_count :: proc() -> int { file_size :: proc(fd: Handle) -> (i64, Errno) { stat, err := wasi.fd_filestat_get(wasi.fd_t(fd)) if err != nil { - return 0, Errno(err) + return 0, Platform_Error(err) } return i64(stat.size), 0 } diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 0ec0b6091..52f7062a0 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -35,6 +35,7 @@ ERROR_INVALID_HANDLE :: _Platform_Error(6) ERROR_NOT_ENOUGH_MEMORY :: _Platform_Error(8) ERROR_NO_MORE_FILES :: _Platform_Error(18) ERROR_HANDLE_EOF :: _Platform_Error(38) +ERROR_EOF :: ERROR_HANDLE_EOF ERROR_NETNAME_DELETED :: _Platform_Error(64) ERROR_FILE_EXISTS :: _Platform_Error(80) ERROR_INVALID_PARAMETER :: _Platform_Error(87) @@ -62,14 +63,15 @@ ERROR_NEGATIVE_OFFSET :: _Platform_Error(1<<29 + 2) // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() - - +get_last_error :: proc "contextless" () -> Error { + return Platform_Error(win32.GetLastError()) +} last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { file_info: win32.BY_HANDLE_FILE_INFORMATION if !win32.GetFileInformationByHandle(win32.HANDLE(fd), &file_info) { - return 0, Errno(win32.GetLastError()) + return 0, Platform_Error(win32.GetLastError()) } lo := File_Time(file_info.ftLastWriteTime.dwLowDateTime) hi := File_Time(file_info.ftLastWriteTime.dwHighDateTime) @@ -81,7 +83,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) { wide_path := win32.utf8_to_wstring(name) if !win32.GetFileAttributesExW(wide_path, win32.GetFileExInfoStandard, &data) { - return 0, Errno(win32.GetLastError()) + return 0, Platform_Error(win32.GetLastError()) } l := File_Time(data.ftLastWriteTime.dwLowDateTime) diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin index 4bb3bd4c4..d584749cc 100644 --- a/core/os/stat_windows.odin +++ b/core/os/stat_windows.odin @@ -19,7 +19,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa for { n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) if n == 0 { - return "", Errno(win32.GetLastError()) + return "", Platform_Error(win32.GetLastError()) } if n <= u32(len(buf)) { return win32.utf16_to_utf8(buf[:n], allocator) or_else "", ERROR_NONE @@ -54,7 +54,7 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al fd: win32.WIN32_FIND_DATAW sh := win32.FindFirstFileW(wname, &fd) if sh == win32.INVALID_HANDLE_VALUE { - e = Errno(win32.GetLastError()) + e = Platform_Error(win32.GetLastError()) return } win32.FindClose(sh) @@ -64,7 +64,7 @@ _stat :: proc(name: string, create_file_attributes: u32, allocator := context.al h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil) if h == win32.INVALID_HANDLE_VALUE { - e = Errno(win32.GetLastError()) + e = Platform_Error(win32.GetLastError()) return } defer win32.CloseHandle(h) @@ -151,7 +151,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ( n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0) if n == 0 { - return nil, Errno(win32.GetLastError()) + return nil, Platform_Error(win32.GetLastError()) } buf := make([]u16, max(n, win32.DWORD(260))+1, allocator) buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0) @@ -273,16 +273,16 @@ file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Errno) { d: win32.BY_HANDLE_FILE_INFORMATION if !win32.GetFileInformationByHandle(h, &d) { - err := Errno(win32.GetLastError()) + err := Platform_Error(win32.GetLastError()) return {}, err } ti: win32.FILE_ATTRIBUTE_TAG_INFO if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) { - err := win32.GetLastError() - if err != u32(ERROR_INVALID_PARAMETER) { - return {}, Errno(err) + err := Platform_Error(win32.GetLastError()) + if err != ERROR_INVALID_PARAMETER { + return {}, err } // Indicate this is a symlink on FAT file systems ti.ReparseTag = 0 diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin index 5ebd2cdc2..ae26e1394 100644 --- a/core/path/filepath/path_windows.odin +++ b/core/path/filepath/path_windows.odin @@ -63,14 +63,14 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Errno) { p := win32.utf8_to_utf16(name, ta) n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil) if n == 0 { - return "", os.Errno(win32.GetLastError()) + return "", os.Platform_Error(win32.GetLastError()) } buf := make([]u16, n, ta) n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) if n == 0 { delete(buf) - return "", os.Errno(win32.GetLastError()) + return "", os.Platform_Error(win32.GetLastError()) } return win32.utf16_to_utf8(buf[:n], ta) or_else "", os.ERROR_NONE diff --git a/core/prof/spall/spall_windows.odin b/core/prof/spall/spall_windows.odin index 4d96c111a..a55c42852 100644 --- a/core/prof/spall/spall_windows.odin +++ b/core/prof/spall/spall_windows.odin @@ -25,7 +25,7 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (int, os.Errno) #n e := win32.WriteFile(win32.HANDLE(fd), &data[total_write], to_write, &single_write_length, nil) if single_write_length <= 0 || !e { - err := os.Errno(win32.GetLastError()) + err := os.Platform_Error(win32.GetLastError()) return int(total_write), err } total_write += i64(single_write_length) diff --git a/core/sys/wasm/wasi/wasi_api.odin b/core/sys/wasm/wasi/wasi_api.odin index 22abd8dc4..6ae6c9151 100644 --- a/core/sys/wasm/wasi/wasi_api.odin +++ b/core/sys/wasm/wasi/wasi_api.odin @@ -16,6 +16,7 @@ CLOCK_REALTIME :: clockid_t(2) CLOCK_THREAD_CPUTIME_ID :: clockid_t(3) errno_t :: enum u16 { + NONE = 0, // No error occurred. System call completed successfully. SUCCESS = 0, // Argument list too long. diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 78b88f21a..9df3c7076 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4366,25 +4366,6 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar } switch (t->kind) { - // IMPORTANT NOTE HACK(bill): This is just to allow for comparisons against `0` with the `os.Error` type - // as a kind of transition period - case Type_Enum: - if (operand->mode == Addressing_Constant && - target_type->kind == Type_Named && - target_type->Named.name == "Error") { - Entity *e = target_type->Named.type_name; - if (e->pkg && e->pkg->name == "os") { - if (is_exact_value_zero(operand->value)) { - check_is_expressible(c, operand, t); - if (operand->mode == Addressing_Invalid) { - return; - } - update_untyped_expr_value(c, operand->expr, operand->value); - } - } - } - break; - case Type_Basic: if (operand->mode == Addressing_Constant) { check_is_expressible(c, operand, t); @@ -4478,6 +4459,22 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar case Type_Union: + // IMPORTANT NOTE HACK(bill): This is just to allow for comparisons against `0` with the `os.Error` type + // as a kind of transition period + if (operand->mode == Addressing_Constant && + target_type->kind == Type_Named && + target_type->Named.name == "Error") { + Entity *e = target_type->Named.type_name; + if (e->pkg && e->pkg->name == "os") { + if (is_exact_value_zero(operand->value) && + (operand->value.kind == ExactValue_Integer || + operand->value.kind == ExactValue_Float)) { + update_untyped_expr_value(c, operand->expr, empty_exact_value); + break; + } + } + } + // "fallthrough" if (!is_operand_nil(*operand) && !is_operand_uninit(*operand)) { TEMPORARY_ALLOCATOR_GUARD(); -- cgit v1.2.3 From 1d75a612d54f102ef530c1f58546e3cdb239160c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 11:47:23 +0100 Subject: `os.Errno` -> `os.Error` --- core/flags/errors.odin | 2 +- core/flags/internal_rtti.odin | 2 +- core/path/filepath/path_windows.odin | 2 +- core/path/filepath/walk.odin | 10 +++++----- core/prof/spall/spall.odin | 2 +- core/prof/spall/spall_linux.odin | 4 ++-- core/prof/spall/spall_unix.odin | 4 ++-- core/prof/spall/spall_windows.odin | 2 +- src/check_expr.cpp | 1 + 9 files changed, 15 insertions(+), 14 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/core/flags/errors.odin b/core/flags/errors.odin index 21ea05477..6e48f6ccf 100644 --- a/core/flags/errors.odin +++ b/core/flags/errors.odin @@ -28,7 +28,7 @@ Parse_Error :: struct { // Provides more granular information than what just a string could hold. Open_File_Error :: struct { filename: string, - errno: os.Errno, + errno: os.Error, mode: int, perms: int, } diff --git a/core/flags/internal_rtti.odin b/core/flags/internal_rtti.odin index ac39eaa8b..8838b771d 100644 --- a/core/flags/internal_rtti.odin +++ b/core/flags/internal_rtti.odin @@ -255,7 +255,7 @@ parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type: handle, errno := os.open(str, mode, perms) if errno != 0 { - // NOTE(Feoramund): os.Errno is system-dependent, and there's + // NOTE(Feoramund): os.Error is system-dependent, and there's // currently no good way to translate them all into strings. // // The upcoming `os2` package will hopefully solve this. diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin index ae26e1394..6a9ac9dee 100644 --- a/core/path/filepath/path_windows.odin +++ b/core/path/filepath/path_windows.odin @@ -52,7 +52,7 @@ is_abs :: proc(path: string) -> bool { @(private) -temp_full_path :: proc(name: string) -> (path: string, err: os.Errno) { +temp_full_path :: proc(name: string) -> (path: string, err: os.Error) { ta := context.temp_allocator name := name diff --git a/core/path/filepath/walk.odin b/core/path/filepath/walk.odin index 9ba3165dc..9fd4c455f 100644 --- a/core/path/filepath/walk.odin +++ b/core/path/filepath/walk.odin @@ -14,7 +14,7 @@ import "core:slice" // The sole exception is if 'skip_dir' is returned as true: // when 'skip_dir' is invoked on a directory. 'walk' skips directory contents // when 'skip_dir' is invoked on a non-directory. 'walk' skips the remaining files in the containing directory -Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Errno, user_data: rawptr) -> (err: os.Errno, skip_dir: bool) +Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Error, user_data: rawptr) -> (err: os.Error, skip_dir: bool) // walk walks the file tree rooted at 'root', calling 'walk_proc' for each file or directory in the tree, including 'root' // All errors that happen visiting files and directories are filtered by walk_proc @@ -22,7 +22,7 @@ Walk_Proc :: #type proc(info: os.File_Info, in_err: os.Errno, user_data: rawptr) // NOTE: Walking large directories can be inefficient due to the lexical sort // NOTE: walk does not follow symbolic links // NOTE: os.File_Info uses the 'context.temp_allocator' to allocate, and will delete when it is done -walk :: proc(root: string, walk_proc: Walk_Proc, user_data: rawptr) -> os.Errno { +walk :: proc(root: string, walk_proc: Walk_Proc, user_data: rawptr) -> os.Error { info, err := os.lstat(root, context.temp_allocator) defer os.file_info_delete(info, context.temp_allocator) @@ -37,7 +37,7 @@ walk :: proc(root: string, walk_proc: Walk_Proc, user_data: rawptr) -> os.Errno @(private) -_walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (err: os.Errno, skip_dir: bool) { +_walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (err: os.Error, skip_dir: bool) { if !info.is_dir { if info.fullpath == "" && info.name == "" { // ignore empty things @@ -47,7 +47,7 @@ _walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (e } fis: []os.File_Info - err1: os.Errno + err1: os.Error fis, err = read_dir(info.fullpath, context.temp_allocator) defer os.file_info_slice_delete(fis, context.temp_allocator) @@ -70,7 +70,7 @@ _walk :: proc(info: os.File_Info, walk_proc: Walk_Proc, user_data: rawptr) -> (e } @(private) -read_dir :: proc(dir_name: string, allocator := context.temp_allocator) -> ([]os.File_Info, os.Errno) { +read_dir :: proc(dir_name: string, allocator := context.temp_allocator) -> ([]os.File_Info, os.Error) { f, err := os.open(dir_name, os.O_RDONLY) if err != 0 { return nil, err diff --git a/core/prof/spall/spall.odin b/core/prof/spall/spall.odin index a6fc59e74..38c563248 100644 --- a/core/prof/spall/spall.odin +++ b/core/prof/spall/spall.odin @@ -227,7 +227,7 @@ _buffer_end :: proc "contextless" (ctx: ^Context, buffer: ^Buffer) #no_bounds_ch } @(no_instrumentation) -write :: proc "contextless" (fd: os.Handle, buf: []byte) -> (n: int, err: os.Errno) { +write :: proc "contextless" (fd: os.Handle, buf: []byte) -> (n: int, err: os.Error) { return _write(fd, buf) } diff --git a/core/prof/spall/spall_linux.odin b/core/prof/spall/spall_linux.odin index 3f475c5e0..deee15aa1 100644 --- a/core/prof/spall/spall_linux.odin +++ b/core/prof/spall/spall_linux.odin @@ -10,7 +10,7 @@ import "core:sys/linux" MAX_RW :: 0x7fffffff @(no_instrumentation) -_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Errno) #no_bounds_check /* bounds check would segfault instrumentation */ { +_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { if len(data) == 0 { return 0, os.ERROR_NONE } @@ -19,7 +19,7 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.E chunk := data[:min(len(data), MAX_RW)] written, errno := linux.write(linux.Fd(fd), chunk) if errno != .NONE { - return n, os.Errno(errno) + return n, os.Error(errno) } n += written } diff --git a/core/prof/spall/spall_unix.odin b/core/prof/spall/spall_unix.odin index e6ba7ecde..6da57ee95 100644 --- a/core/prof/spall/spall_unix.odin +++ b/core/prof/spall/spall_unix.odin @@ -30,7 +30,7 @@ get_last_error :: proc "contextless" () -> os.Platform_Error { MAX_RW :: 0x7fffffff @(no_instrumentation) -_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Errno) #no_bounds_check /* bounds check would segfault instrumentation */ { +_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { if len(data) == 0 { return 0, os.ERROR_NONE } @@ -39,7 +39,7 @@ _write :: proc "contextless" (fd: os.Handle, data: []byte) -> (n: int, err: os.E chunk := data[:min(len(data), MAX_RW)] written := _unix_write(fd, raw_data(chunk), len(chunk)) if written < 0 { - return n, os.Errno(get_last_error()) + return n, os.Error(get_last_error()) } n += written } diff --git a/core/prof/spall/spall_windows.odin b/core/prof/spall/spall_windows.odin index a55c42852..105a61891 100644 --- a/core/prof/spall/spall_windows.odin +++ b/core/prof/spall/spall_windows.odin @@ -10,7 +10,7 @@ import win32 "core:sys/windows" MAX_RW :: 1<<30 @(no_instrumentation) -_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (int, os.Errno) #no_bounds_check /* bounds check would segfault instrumentation */ { +_write :: proc "contextless" (fd: os.Handle, data: []byte) -> (int, os.Error) #no_bounds_check /* bounds check would segfault instrumentation */ { if len(data) == 0 { return 0, os.ERROR_NONE } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9df3c7076..9efd16af4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4463,6 +4463,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar // as a kind of transition period if (operand->mode == Addressing_Constant && target_type->kind == Type_Named && + (c->pkg == nullptr || c->pkg->name != "os") && target_type->Named.name == "Error") { Entity *e = target_type->Named.type_name; if (e->pkg && e->pkg->name == "os") { -- cgit v1.2.3 From 5187bb68bb46a508c90c83861973c57b8e89d005 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 12:08:52 +0100 Subject: Hack: Convert `0` to `nil` --- src/check_expr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9efd16af4..06784a7f3 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4470,7 +4470,10 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar if (is_exact_value_zero(operand->value) && (operand->value.kind == ExactValue_Integer || operand->value.kind == ExactValue_Float)) { - update_untyped_expr_value(c, operand->expr, empty_exact_value); + operand->mode = Addressing_Value; + target_type = t_untyped_nil; + operand->value = empty_exact_value; + update_untyped_expr_value(c, operand->expr, operand->value); break; } } -- cgit v1.2.3 From 0bedd3357ae709c1d35e86ce6e883964fea13fdd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 4 Aug 2024 14:58:12 +0100 Subject: Disallow `err != 0` with `os.Error` when `-strict-style` is enabled --- src/check_expr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 06784a7f3..b291cbe70 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4461,7 +4461,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar case Type_Union: // IMPORTANT NOTE HACK(bill): This is just to allow for comparisons against `0` with the `os.Error` type // as a kind of transition period - if (operand->mode == Addressing_Constant && + if (!build_context.strict_style && + operand->mode == Addressing_Constant && target_type->kind == Type_Named && (c->pkg == nullptr || c->pkg->name != "os") && target_type->Named.name == "Error") { -- cgit v1.2.3 From 6175efde3d4b2ec2cdac172cce0f2d1887705af2 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Mon, 5 Aug 2024 17:23:50 +0200 Subject: Fix crash if referencing import "aliased" in other file. Fixes #4026 --- src/check_expr.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b291cbe70..4bce42129 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5158,6 +5158,14 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod Scope *import_scope = e->ImportName.scope; String entity_name = selector->Ident.token.string; + if (import_scope == nullptr) { + ERROR_BLOCK(); + error(node, "'%.*s' is not imported in this file, '%.*s' is unavailable", LIT(import_name), LIT(entity_name)); + operand->mode = Addressing_Invalid; + operand->expr = node; + return nullptr; + } + check_op_expr = false; entity = scope_lookup_current(import_scope, entity_name); bool allow_builtin = false; -- cgit v1.2.3 From f5fe0de0fd508b5d301708c74e67e7314aa52112 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 10 Aug 2024 23:34:35 +0200 Subject: add clarity for diverging mismatch error --- src/check_expr.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4bce42129..38dc30cfa 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1237,6 +1237,24 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ error_line("\t Got: %s\n", s_got); gb_string_free(s_got); gb_string_free(s_expected); + } else if (same_inputs && same_outputs && + x->Proc.diverging != y->Proc.diverging) { + + gbString s_expected = type_to_string(y); + if (y->Proc.diverging) { + s_expected = gb_string_appendc(s_expected, " -> !"); + } + + gbString s_got = type_to_string(x); + if (x->Proc.diverging) { + s_got = gb_string_appendc(s_got, " -> !"); + } + + error_line("\tNote: One of the procedures is diverging while the other isn't\n"); + error_line("\t Expected: %s\n", s_expected); + error_line("\t Got: %s\n", s_got); + gb_string_free(s_got); + gb_string_free(s_expected); } else if (same_inputs && !same_outputs) { gbString s_expected = type_to_string(y->Proc.results); gbString s_got = type_to_string(x->Proc.results); -- cgit v1.2.3 From a1d518442aa83e7d71f952e8356c974ff8b74a91 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Mon, 12 Aug 2024 23:39:07 +0200 Subject: fix type hint propogation for shift Fixes #3856 --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 38dc30cfa..e92de2d93 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3038,7 +3038,7 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod x->mode = Addressing_Value; if (type_hint) { if (is_type_integer(type_hint)) { - x->type = type_hint; + convert_to_typed(c, x, type_hint); } else { gbString x_str = expr_to_string(x->expr); gbString to_type = type_to_string(type_hint); -- cgit v1.2.3 From 5c06fcd346813a132c4cbaf09e0a410294371a3d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 18 Aug 2024 12:00:27 +0100 Subject: Fix #4064 --- src/check_expr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e92de2d93..d208be642 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6253,7 +6253,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } if (param_is_variadic) { - continue; + if (!named_variadic_param) { + continue; + } } score += eval_param_and_score(c, o, e->type, err, false, e, show_error); } -- cgit v1.2.3 From 60b2979cfd5586175cc8314c8711addc19a07f0c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 18 Aug 2024 12:10:46 +0100 Subject: Fix #4024 --- src/check_expr.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d208be642..9e13b0f24 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5168,7 +5168,14 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod add_entity_use(c, op_expr, e); expr_entity = e; - if (e != nullptr && e->kind == Entity_ImportName && selector->kind == Ast_Ident) { + if (e != nullptr && (e->kind == Entity_Procedure || e->kind == Entity_ProcGroup) && selector->kind == Ast_Ident) { + gbString sel_str = expr_to_string(selector); + error(node, "'%s' is not declared by by '%.*s'", sel_str, LIT(e->token.string)); + gb_string_free(sel_str); + operand->mode = Addressing_Invalid; + operand->expr = node; + return nullptr; + } else if (e != nullptr && e->kind == Entity_ImportName && selector->kind == Ast_Ident) { // IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile // It pretty much needs to be in this order and this way // If you can clean this up, please do but be really careful -- cgit v1.2.3 From b2e64b7ce043e2045551d43400a62a7897c1c430 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sun, 18 Aug 2024 17:09:57 +0200 Subject: implement lshrti3 on wasm --- base/runtime/procs_wasm.odin | 21 +++++++++ src/check_expr.cpp | 100 +++++++++++++++++++++++-------------------- src/checker.cpp | 1 + 3 files changed, 76 insertions(+), 46 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/base/runtime/procs_wasm.odin b/base/runtime/procs_wasm.odin index 7501df460..9f2e9befc 100644 --- a/base/runtime/procs_wasm.odin +++ b/base/runtime/procs_wasm.odin @@ -52,3 +52,24 @@ udivti3 :: proc "c" (la, ha, lb, hb: u64) -> u128 { b.lo, b.hi = lb, hb return udivmodti4(a.all, b.all, nil) } + +@(link_name="__lshrti3", linkage="strong") +__lshrti3 :: proc "c" (la, ha: u64, b: u32) -> i128 { + bits :: size_of(u32)*8 + + input, result: ti_int + input.lo = la + input.hi = ha + + if b & bits != 0 { + result.hi = 0 + result.lo = input.hi >> (b - bits) + } else if b == 0 { + return input.all + } else { + result.hi = input.hi >> b + result.lo = (input.hi << (bits - b)) | (input.lo >> b) + } + + return result.all +} diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9e13b0f24..df138f77c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3935,6 +3935,60 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ return; } + bool REQUIRE = true; + Type *bt = base_type(x->type); + if (op.kind == Token_Mod || op.kind == Token_ModEq || + op.kind == Token_ModMod || op.kind == Token_ModModEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_u128: add_package_dependency(c, "runtime", "umodti3", REQUIRE); break; + case Basic_i128: add_package_dependency(c, "runtime", "modti3", REQUIRE); break; + } + } else if (op.kind == Token_Quo || op.kind == Token_QuoEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_complex32: add_package_dependency(c, "runtime", "quo_complex32"); break; + case Basic_complex64: add_package_dependency(c, "runtime", "quo_complex64"); break; + case Basic_complex128: add_package_dependency(c, "runtime", "quo_complex128"); break; + case Basic_quaternion64: add_package_dependency(c, "runtime", "quo_quaternion64"); break; + case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break; + case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break; + + case Basic_u128: add_package_dependency(c, "runtime", "udivti3", REQUIRE); break; + case Basic_i128: add_package_dependency(c, "runtime", "divti3", REQUIRE); break; + } + } else if (op.kind == Token_Mul || op.kind == Token_MulEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break; + case Basic_quaternion128: add_package_dependency(c, "runtime", "mul_quaternion128"); break; + case Basic_quaternion256: add_package_dependency(c, "runtime", "mul_quaternion256"); break; + + + case Basic_u128: + case Basic_i128: + if (is_arch_wasm()) { + add_package_dependency(c, "runtime", "__multi3", REQUIRE); + } + break; + } + } else if (op.kind == Token_Shl || op.kind == Token_ShlEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_u128: + case Basic_i128: + if (is_arch_wasm()) { + add_package_dependency(c, "runtime", "__ashlti3", REQUIRE); + } + break; + } + } else if (op.kind == Token_Shr || op.kind == Token_ShrEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_u128: + case Basic_i128: + if (is_arch_wasm()) { + add_package_dependency(c, "runtime", "__lshrti3", REQUIRE); + } + break; + } + } + if (token_is_shift(op.kind)) { check_shift(c, x, y, node, type_hint); return; @@ -4103,52 +4157,6 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ return; } - bool REQUIRE = true; - - Type *bt = base_type(x->type); - if (op.kind == Token_Mod || op.kind == Token_ModEq || - op.kind == Token_ModMod || op.kind == Token_ModModEq) { - if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_u128: add_package_dependency(c, "runtime", "umodti3", REQUIRE); break; - case Basic_i128: add_package_dependency(c, "runtime", "modti3", REQUIRE); break; - } - } else if (op.kind == Token_Quo || op.kind == Token_QuoEq) { - if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_complex32: add_package_dependency(c, "runtime", "quo_complex32"); break; - case Basic_complex64: add_package_dependency(c, "runtime", "quo_complex64"); break; - case Basic_complex128: add_package_dependency(c, "runtime", "quo_complex128"); break; - case Basic_quaternion64: add_package_dependency(c, "runtime", "quo_quaternion64"); break; - case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break; - case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break; - - case Basic_u128: add_package_dependency(c, "runtime", "udivti3", REQUIRE); break; - case Basic_i128: add_package_dependency(c, "runtime", "divti3", REQUIRE); break; - } - } else if (op.kind == Token_Mul || op.kind == Token_MulEq) { - if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break; - case Basic_quaternion128: add_package_dependency(c, "runtime", "mul_quaternion128"); break; - case Basic_quaternion256: add_package_dependency(c, "runtime", "mul_quaternion256"); break; - - - case Basic_u128: - case Basic_i128: - if (is_arch_wasm()) { - add_package_dependency(c, "runtime", "__multi3", REQUIRE); - } - break; - } - } else if (op.kind == Token_Shl || op.kind == Token_ShlEq) { - if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_u128: - case Basic_i128: - if (is_arch_wasm()) { - add_package_dependency(c, "runtime", "__ashlti3", REQUIRE); - } - break; - } - } - x->mode = Addressing_Value; } diff --git a/src/checker.cpp b/src/checker.cpp index 6571f696a..c8eaf0acc 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2723,6 +2723,7 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { // WASM Specific str_lit("__ashlti3"), str_lit("__multi3"), + str_lit("__lshrti3"), ); FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_rtti, -- cgit v1.2.3 From d99a6ad003a3606f877abfc1745090007674b76b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 18 Aug 2024 22:52:57 +0100 Subject: Add suggestion for `~uint(0)` if `cast(uint)-1` is done --- src/check_expr.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index df138f77c..f4d5cc5a4 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2332,14 +2332,24 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, } BigInt *bi = &o->value.value_integer; if (is_type_unsigned(type)) { + BigInt one = big_int_make_u64(1); + BigInt max_size = big_int_make_u64(1); + BigInt bits = big_int_make_i64(bit_size); + big_int_shl_eq(&max_size, &bits); + big_int_sub_eq(&max_size, &one); + if (big_int_is_neg(bi)) { error_line("\tA negative value cannot be represented by the unsigned integer type '%s'\n", b); + BigInt dst = {}; + big_int_neg(&dst, bi); + if (big_int_cmp(&dst, &max_size) < 0) { + big_int_sub_eq(&dst, &one); + String dst_str = big_int_to_string(temporary_allocator(), &dst); + gbString t = type_to_string(type); + error_line("\tSuggestion: ~%s(%.*s)\n", t, LIT(dst_str)); + gb_string_free(t); + } } else { - BigInt one = big_int_make_u64(1); - BigInt max_size = big_int_make_u64(1); - BigInt bits = big_int_make_i64(bit_size); - big_int_shl_eq(&max_size, &bits); - big_int_sub_eq(&max_size, &one); String max_size_str = big_int_to_string(temporary_allocator(), &max_size); if (size_changed) { -- cgit v1.2.3 From 6b4b0cea5dd0b451a283f919e36fa6c060f2f236 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 20 Aug 2024 22:12:47 +0200 Subject: Add table-driven (in)definite article to some errors. --- src/check_expr.cpp | 22 +++++++++++++++------- src/error.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 7 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f4d5cc5a4..2540230df 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1071,16 +1071,19 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ return; } + // Grab definite or indefinite article matching `context_name`, or "" if not found. + String article = error_article(context_name); + if (is_type_untyped(operand->type)) { Type *target_type = type; if (type == nullptr || is_type_any(type)) { if (type == nullptr && is_type_untyped_uninit(operand->type)) { - error(operand->expr, "Use of --- in %.*s", LIT(context_name)); + error(operand->expr, "Use of --- in %.*s%.*s", LIT(article), LIT(context_name)); operand->mode = Addressing_Invalid; return; } if (type == nullptr && is_type_untyped_nil(operand->type)) { - error(operand->expr, "Use of untyped nil in %.*s", LIT(context_name)); + error(operand->expr, "Use of untyped nil in %.*s%.*s", LIT(article), LIT(context_name)); operand->mode = Addressing_Invalid; return; } @@ -1135,9 +1138,10 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ // TODO(bill): is this a good enough error message? error(operand->expr, - "Cannot assign overloaded procedure group '%s' to '%s' in %.*s", + "Cannot assign overloaded procedure group '%s' to '%s' in %.*s%.*s", expr_str, op_type_str, + LIT(article), LIT(context_name)); operand->mode = Addressing_Invalid; } @@ -1163,20 +1167,23 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ switch (operand->mode) { case Addressing_Builtin: error(operand->expr, - "Cannot assign built-in procedure '%s' in %.*s", + "Cannot assign built-in procedure '%s' to %.*s%.*s", expr_str, + LIT(article), LIT(context_name)); break; case Addressing_Type: if (is_type_polymorphic(operand->type)) { error(operand->expr, - "Cannot assign '%s' which is a polymorphic type in %.*s", + "Cannot assign '%s' — a polymorphic type — to %.*s%.*s", op_type_str, + LIT(article), LIT(context_name)); } else { error(operand->expr, - "Cannot assign '%s' which is a type in %.*s", + "Cannot assign '%s' — a type — to %.*s%.*s", op_type_str, + LIT(article), LIT(context_name)); } break; @@ -1203,10 +1210,11 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ ERROR_BLOCK(); error(operand->expr, - "Cannot assign value '%s' of type '%s%s' to '%s%s' in %.*s", + "Cannot assign value '%s' of type '%s%s' to '%s%s' in %.*s%.*s", expr_str, op_type_str, op_type_extra, type_str, type_extra, + LIT(article), LIT(context_name)); check_assignment_error_suggestion(c, operand, type); diff --git a/src/error.cpp b/src/error.cpp index f95123f15..1492b00c7 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -820,6 +820,35 @@ gb_internal int error_value_cmp(void const *a, void const *b) { return token_pos_cmp(x->pos, y->pos); } +gb_global String error_article_table[][2] = { + {str_lit("a "), str_lit("bit_set literal")}, + {str_lit("a "), str_lit("constant declaration")}, + {str_lit("a "), str_lit("dynamiic array literal")}, + {str_lit("a "), str_lit("map index")}, + {str_lit("a "), str_lit("map literal")}, + {str_lit("a "), str_lit("matrix literal")}, + {str_lit("a "), str_lit("polymorphic type argument")}, + {str_lit("a "), str_lit("procedure argument")}, + {str_lit("a "), str_lit("simd vector literal")}, + {str_lit("a "), str_lit("slice literal")}, + {str_lit("a "), str_lit("structure literal")}, + {str_lit("a "), str_lit("variable declaration")}, + {str_lit("an "), str_lit("'any' literal")}, + {str_lit("an "), str_lit("array literal")}, + {str_lit("an "), str_lit("enumerated array literal")}, + +}; + +// Returns definite or indefinite article matching `context_name`, or "" if not found. +gb_internal String error_article(String context_name) { + for (int i = 0; i < gb_count_of(error_article_table); i += 1) { + if (context_name == error_article_table[i][1]) { + return error_article_table[i][0]; + } + } + return str_lit(""); +} + gb_internal bool errors_already_printed = false; gb_internal void print_all_errors(void) { -- cgit v1.2.3 From 1bcc0742234d5cf1066e73384bd618ddab792e86 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 21 Aug 2024 14:18:12 +0200 Subject: dash --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2540230df..95b0872ac 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1175,13 +1175,13 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ case Addressing_Type: if (is_type_polymorphic(operand->type)) { error(operand->expr, - "Cannot assign '%s' — a polymorphic type — to %.*s%.*s", + "Cannot assign '%s' - a polymorphic type - to %.*s%.*s", op_type_str, LIT(article), LIT(context_name)); } else { error(operand->expr, - "Cannot assign '%s' — a type — to %.*s%.*s", + "Cannot assign '%s' - a type - to %.*s%.*s", op_type_str, LIT(article), LIT(context_name)); -- cgit v1.2.3 From 07aedb0b89c5ac4fa2607f446a7f3994159e11c3 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Wed, 21 Aug 2024 18:42:11 +0200 Subject: , --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 95b0872ac..9cdba2710 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1175,13 +1175,13 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ case Addressing_Type: if (is_type_polymorphic(operand->type)) { error(operand->expr, - "Cannot assign '%s' - a polymorphic type - to %.*s%.*s", + "Cannot assign '%s', a polymorphic type, to %.*s%.*s", op_type_str, LIT(article), LIT(context_name)); } else { error(operand->expr, - "Cannot assign '%s' - a type - to %.*s%.*s", + "Cannot assign '%s', a type, to %.*s%.*s", op_type_str, LIT(article), LIT(context_name)); -- cgit v1.2.3 From c969bee86d300871103d8cc1441e37f5c60e2b86 Mon Sep 17 00:00:00 2001 From: fusion32 Date: Fri, 23 Aug 2024 17:18:10 -0300 Subject: fix ambiguous generic type names --- src/check_expr.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9cdba2710..b06f804ae 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7625,7 +7625,7 @@ 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)); - TypeTuple *tuple = get_record_polymorphic_params(e->type); + TypeTuple *tuple = get_record_polymorphic_params(bt); if (tuple != nullptr) for_array(i, tuple->variables) { Entity *v = tuple->variables[i]; String name = v->token.string; @@ -7640,8 +7640,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O s = write_type_to_string(s, v->type, false); } } else if (v->kind == Entity_Constant) { - s = gb_string_append_fmt(s, "="); - s = write_exact_value_to_string(s, v->Constant.value); + if (v->type->kind != ExactValue_Invalid) { + s = gb_string_append_fmt(s, "="); + s = write_exact_value_to_string(s, v->Constant.value); + } } } s = gb_string_append_fmt(s, ")"); -- cgit v1.2.3 From 5ef8a092f663d5a092c6eff026ce3122020da349 Mon Sep 17 00:00:00 2001 From: fusion32 Date: Fri, 23 Aug 2024 17:50:27 -0300 Subject: fix wrong exact value kind comparison --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b06f804ae..1a5b8c9a7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7640,7 +7640,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O s = write_type_to_string(s, v->type, false); } } else if (v->kind == Entity_Constant) { - if (v->type->kind != ExactValue_Invalid) { + if (v->Constant.value.kind != ExactValue_Invalid) { s = gb_string_append_fmt(s, "="); s = write_exact_value_to_string(s, v->Constant.value); } -- cgit v1.2.3 From 4458ca4585666b1e2bc9438b6a2402a1ad93bbc2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 11:40:02 +0100 Subject: Fix #4126 --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9cdba2710..24cc8868a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3782,10 +3782,10 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ // NOTE(bill): Allow comparisons between types if (is_ise_expr(be->left)) { // Evalute the right before the left for an '.X' expression - check_expr_or_type(c, y, be->right, type_hint); + check_expr_or_type(c, y, be->right, nullptr /* ignore type hint */); check_expr_or_type(c, x, be->left, y->type); } else { - check_expr_or_type(c, x, be->left, type_hint); + check_expr_or_type(c, x, be->left, nullptr /* ignore type hint */); check_expr_or_type(c, y, be->right, x->type); } bool xt = x->mode == Addressing_Type; -- cgit v1.2.3 From 68a83abcd62210fac764806445fd28296d722c26 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 11:44:59 +0100 Subject: #4119 Add error when doing `{.A | .B}` instead of `{.A, .B}` with a suggestion to do surround it in parentheses to make it clear it is intended --- src/check_expr.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 24cc8868a..8e16bd0e9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -10055,6 +10055,22 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * is_constant = o->mode == Addressing_Constant; } + if (elem->kind == Ast_BinaryExpr) { + switch (elem->BinaryExpr.op.kind) { + case Token_Or: + { + gbString x = expr_to_string(elem->BinaryExpr.left); + gbString y = expr_to_string(elem->BinaryExpr.right); + gbString e = expr_to_string(elem); + error(elem, "Was the following intended? '%s, %s'; if not, surround the expression with parentheses '(%s)'", x, y, e); + gb_string_free(e); + gb_string_free(y); + gb_string_free(x); + } + break; + } + } + check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal")); if (o->mode == Addressing_Constant) { i64 lower = t->BitSet.lower; -- cgit v1.2.3 From 00fb60d3d96877935012a4cc9cbd39525dc52d17 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 11:48:32 +0100 Subject: #4115 Add `Suggestion: 'typeid_of(T)'` --- src/check_expr.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8e16bd0e9..a2500048e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1180,11 +1180,15 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ LIT(article), LIT(context_name)); } else { + ERROR_BLOCK(); error(operand->expr, "Cannot assign '%s', a type, to %.*s%.*s", op_type_str, LIT(article), LIT(context_name)); + if (type && are_types_identical(type, t_any)) { + error_line("\tSuggestion: 'typeid_of(%s)'", expr_str); + } } break; default: -- cgit v1.2.3 From ca4d91a8a33c2209ef9f6708fb5effc278a2b9f5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 12:26:41 +0100 Subject: Fix #4079 --- src/check_expr.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index a878911d9..7ac09ac56 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4662,7 +4662,8 @@ gb_internal bool check_index_value(CheckerContext *c, Type *main_type, bool open check_expr_with_type_hint(c, &operand, index_value, type_hint); if (operand.mode == Addressing_Invalid) { if (value) *value = 0; - return false; + // NOTE(bill): return true here to propagate the errors better + return true; } Type *index_type = t_int; @@ -4883,7 +4884,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v TypeAndValue tav = fv->value->tav; if (success_) *success_ = true; if (finish_) *finish_ = false; - return tav.value;; + return tav.value; } } @@ -4958,7 +4959,6 @@ gb_internal ExactValue get_constant_field(CheckerContext *c, Operand const *oper return value; } } - if (success_) *success_ = true; return value; } else if (value.kind == ExactValue_Quaternion) { @@ -10566,7 +10566,8 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, o->expr = node; return kind; } else if (ok && !is_type_matrix(t)) { - ExactValue value = type_and_value_of_expr(ie->expr).value; + TypeAndValue tav = type_and_value_of_expr(ie->expr); + ExactValue value = tav.value; o->mode = Addressing_Constant; bool success = false; bool finish = false; -- cgit v1.2.3 From 38ea276231cba6860ac013ffb338b96afb6cd2fa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 30 Aug 2024 10:48:21 +0100 Subject: Make `~some_bit_set` work on only the possible bits by doing a mask with the full set --- src/check_expr.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++++++- src/llvm_backend_expr.cpp | 12 ++++++- 2 files changed, 96 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7ac09ac56..ba198b5ca 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2575,6 +2575,84 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable; } +gb_internal ExactValue exact_bit_set_all_set_mask(Type *type) { + type = base_type(type); + GB_ASSERT(type->kind == Type_BitSet); + + i64 lower = type->BitSet.lower; + i64 upper = type->BitSet.upper; + Type *elem = type->BitSet.elem; + Type *underlying = type->BitSet.underlying; + bool is_backed = underlying != nullptr; + gb_unused(is_backed); + + BigInt b_lower = {}; + BigInt b_upper = {}; + big_int_from_i64(&b_lower, lower); + big_int_from_i64(&b_upper, upper); + + + BigInt one = {}; + big_int_from_u64(&one, 1); + + BigInt mask = {}; + + if (elem == nullptr) { + big_int_from_i64(&mask, -1); + } else if (is_type_enum(elem)) { + Type *e = base_type(elem); + GB_ASSERT(e->kind == Type_Enum); + gb_unused(e); + + if ((big_int_cmp(&e->Enum.min_value->value_integer, &b_lower) == 0 || is_backed) && + big_int_cmp(&e->Enum.max_value->value_integer, &b_upper) == 0) { + + i64 lower_base = is_backed ? gb_min(0, lower) : lower; + BigInt b_lower_base = {}; + big_int_from_i64(&b_lower_base, lower_base); + + for (Entity *f : e->Enum.fields) { + if (f->kind != Entity_Constant) { + continue; + } + if (f->Constant.value.kind != ExactValue_Integer) { + continue; + } + + BigInt shift_amount = f->Constant.value.value_integer; + big_int_sub_eq(&shift_amount, &b_lower_base); + + + BigInt value = {}; + big_int_shl(&value, &one, &shift_amount); + + big_int_or(&mask, &mask, &value); + } + + } else { + // TODO(bill): enum range based + big_int_from_i64(&mask, -1); + } + } else { + i64 lower_base = lower; + for (i64 x = lower; x <= upper; x++) { + BigInt shift_amount = {}; + big_int_from_i64(&shift_amount, x - lower_base); + + BigInt value = {}; + big_int_shl(&value, &one, &shift_amount); + + big_int_or(&mask, &mask, &value); + } + } + + + ExactValue res = {}; + res.kind = ExactValue_Integer; + res.value_integer = mask; + return res; +} + gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { switch (op.kind) { case Token_And: { // Pointer address @@ -2714,6 +2792,10 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * } o->value = exact_unary_operator_value(op.kind, o->value, precision, is_unsigned); + if (op.kind == Token_Xor && is_type_bit_set(type)) { + ExactValue mask = exact_bit_set_all_set_mask(type); + o->value = exact_binary_operator_value(Token_And, o->value, mask); + } if (is_type_typed(type)) { if (node != nullptr) { @@ -10085,7 +10167,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (lower <= v && v <= upper) { // okay } else { - error(elem, "Bit field value out of bounds, %lld not in the range %lld .. %lld", v, lower, upper); + gbString s = expr_to_string(o->expr); + error(elem, "Bit field value out of bounds, %s (%lld) not in the range %lld .. %lld", s, v, lower, upper); + gb_string_free(s); continue; } } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index c2707612a..b10b7745a 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -136,6 +136,11 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, switch (op) { case Token_Xor: opv = LLVMBuildNot(p->builder, v, ""); + if (is_type_bit_set(elem_type)) { + ExactValue ev_mask = exact_bit_set_all_set_mask(elem_type); + lbValue mask = lb_const_value(p->module, elem_type, ev_mask); + opv = LLVMBuildAnd(p->builder, opv, mask.value, ""); + } break; case Token_Sub: if (is_type_float(elem_type)) { @@ -176,8 +181,13 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, if (op == Token_Xor) { lbValue cmp = {}; - cmp.value = LLVMBuildNot(p->builder, x.value, ""); cmp.type = x.type; + cmp.value = LLVMBuildNot(p->builder, x.value, ""); + if (is_type_bit_set(x.type)) { + ExactValue ev_mask = exact_bit_set_all_set_mask(x.type); + lbValue mask = lb_const_value(p->module, x.type, ev_mask); + cmp.value = LLVMBuildAnd(p->builder, cmp.value, mask.value, ""); + } return lb_emit_conv(p, cmp, type); } -- cgit v1.2.3 From 476030dd2890a4fc0c46afcd8dab3247982a3bd7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 31 Aug 2024 13:51:35 +0100 Subject: Fix #4156 --- src/check_expr.cpp | 2 +- src/llvm_backend_stmt.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ba198b5ca..3b0198431 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2630,7 +2630,7 @@ gb_internal ExactValue exact_bit_set_all_set_mask(Type *type) { } } else { - // TODO(bill): enum range based + // TODO(bill): enum range based"); big_int_from_i64(&mask, -1); } } else { diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index f2fe4f7dc..bef516283 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1404,6 +1404,10 @@ gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, boo } + if (is_typeid) { + return false; + } + return true; } -- cgit v1.2.3 From b4bdb73158d1c6ec8d3b16d2d5f956e749a98817 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 31 Aug 2024 15:06:20 +0100 Subject: Fix `new(sync.Mutex)` --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3b0198431..cbfde4f4b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5738,7 +5738,7 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals gb_internal bool check_no_copy_assignment(Operand const &o, String const &context) { if (o.type && is_type_no_copy(o.type)) { Ast *expr = unparen_expr(o.expr); - if (expr && o.mode != Addressing_Constant) { + if (expr && o.mode != Addressing_Constant && o.mode != Addressing_Type) { if (expr->kind == Ast_CallExpr) { // Okay } else { -- cgit v1.2.3 From 9871ad5fc8c0bd2a3ae63c5446d65dda832385b0 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 1 Sep 2024 17:50:50 -0400 Subject: Remove extra format item at end of `context` error message --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cbfde4f4b..6ab87da09 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -10928,7 +10928,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast case Token_context: { if (c->proc_name.len == 0 && c->curr_proc_sig == nullptr) { - error(node, "'context' is only allowed within procedures %p", c->curr_proc_decl); + error(node, "'context' is only allowed within procedures"); return kind; } if (unparen_expr(c->assignment_lhs_hint) == node) { -- cgit v1.2.3 From 564c7821c59c0ea8244f281587920e42ce701009 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 10 Sep 2024 04:27:16 +0200 Subject: Allow ExactValue_Invalid in assert. Fixes #4225 --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6ab87da09..27ba2448e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3615,7 +3615,7 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type if (is_type_integer(src_t) && is_type_integer(dst_t)) { if (types_have_same_internal_endian(src_t, dst_t)) { ExactValue src_v = exact_value_to_integer(o->value); - GB_ASSERT(src_v.kind == ExactValue_Integer); + GB_ASSERT(src_v.kind == ExactValue_Integer || src_v.kind == ExactValue_Invalid); BigInt v = src_v.value_integer; BigInt smax = {}; -- cgit v1.2.3 From 9b06ea5bfd57c386194438a6a1afd34aa18bb229 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 11 Sep 2024 12:01:01 +0100 Subject: Fix #4229 for edge case `os.Error`/`os.Errno` legacy bodge --- src/check_expr.cpp | 2 +- src/llvm_backend_expr.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 27ba2448e..45c3e9a3c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4602,7 +4602,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar (operand->value.kind == ExactValue_Integer || operand->value.kind == ExactValue_Float)) { operand->mode = Addressing_Value; - target_type = t_untyped_nil; + // target_type = t_untyped_nil; operand->value = empty_exact_value; update_untyped_expr_value(c, operand->expr, operand->value); break; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index f20c52e88..58467db2e 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3451,8 +3451,14 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { switch (expr->kind) { case_ast_node(bl, BasicLit, expr); + if (type != nullptr && type->Named.name == "Error") { + Entity *e = type->Named.type_name; + if (e->pkg && e->pkg->name == "os") { + return lb_const_nil(p->module, type); + } + } TokenPos pos = bl->token.pos; - GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(token_strings[bl->token.kind])); + GB_PANIC("Non-constant basic literal %s - %.*s (%s)", token_pos_to_string(pos), LIT(token_strings[bl->token.kind]), type_to_string(type)); case_end; case_ast_node(bd, BasicDirective, expr); -- cgit v1.2.3 From 27ed10746db72fd3e5ba9aea922cb064aa3f8995 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 11 Sep 2024 23:08:38 +0100 Subject: Allow `transmute(Bit_Set)~T(0)` --- src/check_expr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 45c3e9a3c..760551a72 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3612,7 +3612,8 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type if (are_types_identical(src_bt, dst_bt)) { return true; } - if (is_type_integer(src_t) && is_type_integer(dst_t)) { + if ((is_type_integer(src_t) && is_type_integer(dst_t)) || + is_type_integer(src_t) && is_type_bit_set(dst_t)) { if (types_have_same_internal_endian(src_t, dst_t)) { ExactValue src_v = exact_value_to_integer(o->value); GB_ASSERT(src_v.kind == ExactValue_Integer || src_v.kind == ExactValue_Invalid); -- cgit v1.2.3 From 387f56634d337152d7aba07b740cf5821db9e67f Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 12 Sep 2024 02:16:04 +0200 Subject: fix reuse of slice for varargs with poly types --- src/check_expr.cpp | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 760551a72..f1bf86992 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6204,22 +6204,6 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A Entity *vt = pt->params->Tuple.variables[pt->variadic_index]; o.type = vt->type; - - // NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameters with the backing array - if (c->decl) { - bool found = false; - for (auto &vr : c->decl->variadic_reuses) { - if (are_types_identical(vt->type, vr.slice_type)) { - vr.max_count = gb_max(vr.max_count, variadic_operands.count); - found = true; - break; - } - } - if (!found) { - array_add(&c->decl->variadic_reuses, VariadicReuseData{vt->type, variadic_operands.count}); - } - } - } else { dummy_argument_count += 1; o.type = t_untyped_nil; @@ -6413,6 +6397,23 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } score += eval_param_and_score(c, o, t, err, true, var_entity, show_error); } + + if (!vari_expand && variadic_operands.count != 0) { + // NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameters with the backing array + if (c->decl) { + bool found = false; + for (auto &vr : c->decl->variadic_reuses) { + if (are_types_identical(slice, vr.slice_type)) { + vr.max_count = gb_max(vr.max_count, variadic_operands.count); + found = true; + break; + } + } + if (!found) { + array_add(&c->decl->variadic_reuses, VariadicReuseData{slice, variadic_operands.count}); + } + } + } } if (data) { -- cgit v1.2.3 From 3166c7bef921dcf48ac233738ec2064362bcbbd8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 12 Sep 2024 10:07:09 +0100 Subject: Add `Suggested Example` for using an inline procedure which enables a target feature --- src/check_expr.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f1bf86992..7f82fb58a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8087,7 +8087,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c 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_BLOCK(); error(call, "Inlined procedure enables target feature '%.*s', this requires the calling procedure to at least enable the same feature", LIT(invalid)); + + error_line("\tSuggested Example: @(enable_target_feature=\"%.*s\")\n", LIT(invalid)); } } } -- 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_expr.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 acbf5c8d9775f66de69206b89390f2f966b53d73 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 19 Sep 2024 05:55:30 -0400 Subject: Forbid labelled or-branch expressions within `defer` --- src/check_expr.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6776094bf..fc1aa62e6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9131,6 +9131,10 @@ gb_internal ExprKind check_or_branch_expr(CheckerContext *c, Operand *o, Ast *no } if (label != nullptr) { + if (c->in_defer) { + error(label, "A labelled '%.*s' cannot be used within a 'defer'", LIT(name)); + return Expr_Expr; + } if (label->kind != Ast_Ident) { error(label, "A branch statement's label name must be an identifier"); return Expr_Expr; -- cgit v1.2.3 From 3ff887c6b6b838e9d4932b78ef1ac9319f522d8f Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 2 Oct 2024 15:55:46 +0200 Subject: fix not erroring on invalid ternary For example: `a: f32 = true ? 1 : len` would get to the back-end without errors. Fixes #1690 --- src/check_expr.cpp | 5 ----- 1 file changed, 5 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fc1aa62e6..3b61e049c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8795,11 +8795,6 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n return kind; } - if (x.type == nullptr || x.type == t_invalid || - y.type == nullptr || y.type == t_invalid) { - return kind; - } - bool use_type_hint = type_hint != nullptr && (is_operand_nil(x) || is_operand_nil(y)); convert_to_typed(c, &x, use_type_hint ? type_hint : y.type); -- cgit v1.2.3 From 417e9bb37fbba501bcbd8787cfa1b570c0fb3b5c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 13 Oct 2024 22:26:04 +0100 Subject: Fix #4373 --- src/check_expr.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3b61e049c..d3141ed84 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -285,7 +285,7 @@ gb_internal void error_operand_no_value(Operand *o) { if (o->mode == Addressing_NoValue) { Ast *x = unparen_expr(o->expr); - if (x->kind == Ast_CallExpr) { + if (x != nullptr && x->kind == Ast_CallExpr) { Ast *p = unparen_expr(x->CallExpr.proc); if (p->kind == Ast_BasicDirective) { String tag = p->BasicDirective.name.string; @@ -297,7 +297,7 @@ gb_internal void error_operand_no_value(Operand *o) { } gbString err = expr_to_string(o->expr); - if (x->kind == Ast_CallExpr) { + if (x != nullptr && x->kind == Ast_CallExpr) { error(o->expr, "'%s' call does not return a value and cannot be used as a value", err); } else { error(o->expr, "'%s' used as a value", err); @@ -3901,6 +3901,12 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ // IMPORTANT NOTE(bill): This uses right-left evaluation in type checking only no in check_expr(c, y, be->right); Type *rhs_type = type_deref(y->type); + if (rhs_type == nullptr) { + error(y->expr, "Cannot use '%.*s' on an expression with no value", LIT(op.string)); + x->mode = Addressing_Invalid; + x->expr = node; + return; + } if (is_type_bit_set(rhs_type)) { Type *elem = base_type(rhs_type)->BitSet.elem; -- cgit v1.2.3 From 7f4ce2e1790e43541def82ee3acf3a0a5307b735 Mon Sep 17 00:00:00 2001 From: Morten Hauke Solvang Date: Sat, 19 Oct 2024 10:25:13 +0200 Subject: Suggestion when assigning enum to bit_set --- src/check_expr.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d3141ed84..5ebc737a5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8475,6 +8475,15 @@ gb_internal ExprKind check_implicit_selector_expr(CheckerContext *c, Operand *o, error(node, "Undeclared name '%.*s' for type '%s'", LIT(name), typ); check_did_you_mean_type(name, bt->Enum.fields); + } else if (is_type_bit_set(th) && is_type_enum(th->BitSet.elem)) { + ERROR_BLOCK(); + + gbString typ = type_to_string(th); + gbString str = expr_to_string(node); + error(node, "Cannot convert enum value to '%s'", typ); + error_line("\tSuggestion: Did you mean '{ %s }'?\n", str); + gb_string_free(typ); + gb_string_free(str); } else { gbString typ = type_to_string(th); gbString str = expr_to_string(node); -- cgit v1.2.3 From f32e27d2e4e4fb45206b5b6c36f5264636979ff7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 27 Oct 2024 11:10:55 +0000 Subject: Fix bug caused due to incorrect type checking looking for `context` not defined in a context --- src/check_expr.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d3141ed84..b22bfe4b6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8008,6 +8008,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c pt = data.gen_entity->type; } } + pt = base_type(pt); if (pt->kind == Type_Proc && pt->Proc.calling_convention == ProcCC_Odin) { if ((c->scope->flags & ScopeFlag_ContextDefined) == 0) { -- cgit v1.2.3 From bbf76fa43eda31ea993eb4a4cba0d79418f80849 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 4 Nov 2024 12:49:43 +0000 Subject: Fix bug for `foo().bar` where `foo()` is a 0-value expression --- src/check_expr.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b22bfe4b6..30ca0af23 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5394,22 +5394,26 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod Type *t = type_deref(operand->type); if (t == nullptr) { error(operand->expr, "Cannot use a selector expression on 0-value expression"); - } else if (is_type_dynamic_array(t)) { - init_mem_allocator(c->checker); - } - sel = lookup_field(operand->type, field_name, operand->mode == Addressing_Type); - entity = sel.entity; + } else { + if (is_type_dynamic_array(t)) { + init_mem_allocator(c->checker); + } else { + sel = lookup_field(operand->type, field_name, operand->mode == Addressing_Type); + entity = sel.entity; - // NOTE(bill): Add type info needed for fields like 'names' - if (entity != nullptr && (entity->flags&EntityFlag_TypeField)) { - add_type_info_type(c, operand->type); - } - if (is_type_enum(operand->type)) { - add_type_info_type(c, operand->type); + // NOTE(bill): Add type info needed for fields like 'names' + if (entity != nullptr && (entity->flags&EntityFlag_TypeField)) { + add_type_info_type(c, operand->type); + } + if (is_type_enum(operand->type)) { + add_type_info_type(c, operand->type); + } + } } } - if (entity == nullptr && selector->kind == Ast_Ident && (is_type_array(type_deref(operand->type)) || is_type_simd_vector(type_deref(operand->type)))) { + if (entity == nullptr && selector->kind == Ast_Ident && operand->type != nullptr && + (is_type_array(type_deref(operand->type)) || is_type_simd_vector(type_deref(operand->type)))) { String field_name = selector->Ident.token.string; if (1 < field_name.len && field_name.len <= 4) { u8 swizzles_xyzw[4] = {'x', 'y', 'z', 'w'}; -- cgit v1.2.3 From a0b35f67f83c834f1212aee16bf6fd9103892d90 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 4 Nov 2024 12:51:54 +0000 Subject: Fix previous commit for arrays --- src/check_expr.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 30ca0af23..651d2dc88 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5397,17 +5397,16 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } else { if (is_type_dynamic_array(t)) { init_mem_allocator(c->checker); - } else { - sel = lookup_field(operand->type, field_name, operand->mode == Addressing_Type); - entity = sel.entity; + } + sel = lookup_field(operand->type, field_name, operand->mode == Addressing_Type); + entity = sel.entity; - // NOTE(bill): Add type info needed for fields like 'names' - if (entity != nullptr && (entity->flags&EntityFlag_TypeField)) { - add_type_info_type(c, operand->type); - } - if (is_type_enum(operand->type)) { - add_type_info_type(c, operand->type); - } + // NOTE(bill): Add type info needed for fields like 'names' + if (entity != nullptr && (entity->flags&EntityFlag_TypeField)) { + add_type_info_type(c, operand->type); + } + if (is_type_enum(operand->type)) { + add_type_info_type(c, operand->type); } } } -- cgit v1.2.3 From e38a08013e1afa1bbd7b8f90ee16cfbdfacfb13f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 14 Nov 2024 16:17:24 +0000 Subject: Remove `#relative` types from the compiler --- base/runtime/core.odin | 12 ---- base/runtime/print.odin | 12 ---- core/fmt/fmt.odin | 12 ---- core/reflect/reflect.odin | 81 +++++++++---------------- core/reflect/types.odin | 32 ---------- examples/demo/demo.odin | 17 ------ src/check_expr.cpp | 64 -------------------- src/check_type.cpp | 37 +----------- src/checker.cpp | 24 -------- src/docs_format.cpp | 3 +- src/docs_writer.cpp | 18 ------ src/llvm_backend.hpp | 4 -- src/llvm_backend_debug.cpp | 11 ---- src/llvm_backend_expr.cpp | 37 +----------- src/llvm_backend_general.cpp | 139 ------------------------------------------- src/llvm_backend_type.cpp | 26 -------- src/llvm_backend_utility.cpp | 6 -- src/types.cpp | 98 ------------------------------ 18 files changed, 31 insertions(+), 602 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index a5a3a4d8c..e47f3ecbc 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -171,14 +171,6 @@ Type_Info_Simd_Vector :: struct { elem_size: int, count: int, } -Type_Info_Relative_Pointer :: struct { - pointer: ^Type_Info, // ^T - base_integer: ^Type_Info, -} -Type_Info_Relative_Multi_Pointer :: struct { - pointer: ^Type_Info, // [^]T - base_integer: ^Type_Info, -} Type_Info_Matrix :: struct { elem: ^Type_Info, elem_size: int, @@ -241,8 +233,6 @@ Type_Info :: struct { Type_Info_Map, Type_Info_Bit_Set, Type_Info_Simd_Vector, - Type_Info_Relative_Pointer, - Type_Info_Relative_Multi_Pointer, Type_Info_Matrix, Type_Info_Soa_Pointer, Type_Info_Bit_Field, @@ -275,8 +265,6 @@ Typeid_Kind :: enum u8 { Map, Bit_Set, Simd_Vector, - Relative_Pointer, - Relative_Multi_Pointer, Matrix, Soa_Pointer, Bit_Field, diff --git a/base/runtime/print.odin b/base/runtime/print.odin index 45f6f01ef..c28fd593d 100644 --- a/base/runtime/print.odin +++ b/base/runtime/print.odin @@ -486,18 +486,6 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_u64(u64(info.count)) print_byte(']') print_type(info.elem) - - case Type_Info_Relative_Pointer: - print_string("#relative(") - print_type(info.base_integer) - print_string(") ") - print_type(info.pointer) - - case Type_Info_Relative_Multi_Pointer: - print_string("#relative(") - print_type(info.base_integer) - print_string(") ") - print_type(info.pointer) case Type_Info_Matrix: print_string("matrix[") diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index dd5c2c6a2..49e9f2e6d 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -3002,18 +3002,6 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { case runtime.Type_Info_Bit_Set: fmt_bit_set(fi, v, verb = verb) - case runtime.Type_Info_Relative_Pointer: - ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id) - absolute_ptr := any{ptr, info.pointer.id} - - fmt_value(fi, absolute_ptr, verb) - - case runtime.Type_Info_Relative_Multi_Pointer: - ptr := reflect.relative_pointer_to_absolute_raw(v.data, info.base_integer.id) - absolute_ptr := any{ptr, info.pointer.id} - - fmt_value(fi, absolute_ptr, verb) - case runtime.Type_Info_Matrix: fmt_matrix(fi, v, verb, info) diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index d547b67ed..7f79acb77 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -31,8 +31,6 @@ Type_Info_Enum :: runtime.Type_Info_Enum Type_Info_Map :: runtime.Type_Info_Map Type_Info_Bit_Set :: runtime.Type_Info_Bit_Set Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector -Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer -Type_Info_Relative_Multi_Pointer :: runtime.Type_Info_Relative_Multi_Pointer Type_Info_Matrix :: runtime.Type_Info_Matrix Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer Type_Info_Bit_Field :: runtime.Type_Info_Bit_Field @@ -67,8 +65,6 @@ Type_Kind :: enum { Map, Bit_Set, Simd_Vector, - Relative_Pointer, - Relative_Multi_Pointer, Matrix, Soa_Pointer, Bit_Field, @@ -80,35 +76,33 @@ type_kind :: proc(T: typeid) -> Type_Kind { ti := type_info_of(T) if ti != nil { switch _ in ti.variant { - case Type_Info_Named: return .Named - case Type_Info_Integer: return .Integer - case Type_Info_Rune: return .Rune - case Type_Info_Float: return .Float - case Type_Info_Complex: return .Complex - case Type_Info_Quaternion: return .Quaternion - case Type_Info_String: return .String - case Type_Info_Boolean: return .Boolean - case Type_Info_Any: return .Any - case Type_Info_Type_Id: return .Type_Id - case Type_Info_Pointer: return .Pointer - case Type_Info_Multi_Pointer: return .Multi_Pointer - case Type_Info_Procedure: return .Procedure - case Type_Info_Array: return .Array - case Type_Info_Enumerated_Array: return .Enumerated_Array - case Type_Info_Dynamic_Array: return .Dynamic_Array - case Type_Info_Slice: return .Slice - case Type_Info_Parameters: return .Tuple - case Type_Info_Struct: return .Struct - case Type_Info_Union: return .Union - case Type_Info_Enum: return .Enum - case Type_Info_Map: return .Map - case Type_Info_Bit_Set: return .Bit_Set - case Type_Info_Simd_Vector: return .Simd_Vector - case Type_Info_Relative_Pointer: return .Relative_Pointer - case Type_Info_Relative_Multi_Pointer: return .Relative_Multi_Pointer - case Type_Info_Matrix: return .Matrix - case Type_Info_Soa_Pointer: return .Soa_Pointer - case Type_Info_Bit_Field: return .Bit_Field + case Type_Info_Named: return .Named + case Type_Info_Integer: return .Integer + case Type_Info_Rune: return .Rune + case Type_Info_Float: return .Float + case Type_Info_Complex: return .Complex + case Type_Info_Quaternion: return .Quaternion + case Type_Info_String: return .String + case Type_Info_Boolean: return .Boolean + case Type_Info_Any: return .Any + case Type_Info_Type_Id: return .Type_Id + case Type_Info_Pointer: return .Pointer + case Type_Info_Multi_Pointer: return .Multi_Pointer + case Type_Info_Procedure: return .Procedure + case Type_Info_Array: return .Array + case Type_Info_Enumerated_Array: return .Enumerated_Array + case Type_Info_Dynamic_Array: return .Dynamic_Array + case Type_Info_Slice: return .Slice + case Type_Info_Parameters: return .Tuple + case Type_Info_Struct: return .Struct + case Type_Info_Union: return .Union + case Type_Info_Enum: return .Enum + case Type_Info_Map: return .Map + case Type_Info_Bit_Set: return .Bit_Set + case Type_Info_Simd_Vector: return .Simd_Vector + case Type_Info_Matrix: return .Matrix + case Type_Info_Soa_Pointer: return .Soa_Pointer + case Type_Info_Bit_Field: return .Bit_Field } } @@ -1488,21 +1482,6 @@ as_string :: proc(a: any) -> (value: string, valid: bool) { return } -@(require_results) -relative_pointer_to_absolute :: proc(a: any) -> rawptr { - if a == nil { return nil } - a := a - ti := runtime.type_info_core(type_info_of(a.id)) - a.id = ti.id - - #partial switch info in ti.variant { - case Type_Info_Relative_Pointer: - return relative_pointer_to_absolute_raw(a.data, info.base_integer.id) - } - return nil -} - - @(require_results) relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) -> rawptr { _handle :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) { @@ -1564,10 +1543,6 @@ as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) { case cstring: value = rawptr(v) case: valid = false } - - case Type_Info_Relative_Pointer: - valid = true - value = relative_pointer_to_absolute_raw(a.data, info.base_integer.id) } return @@ -1677,8 +1652,6 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_ Type_Info_Bit_Set, Type_Info_Enum, Type_Info_Simd_Vector, - Type_Info_Relative_Pointer, - Type_Info_Relative_Multi_Pointer, Type_Info_Soa_Pointer, Type_Info_Matrix: return runtime.memory_compare(a.data, b.data, t.size) == 0 diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 4f0674dc8..cb31a27e2 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -158,14 +158,6 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { case Type_Info_Simd_Vector: y := b.variant.(Type_Info_Simd_Vector) or_return return x.count == y.count && x.elem == y.elem - - case Type_Info_Relative_Pointer: - y := b.variant.(Type_Info_Relative_Pointer) or_return - return x.base_integer == y.base_integer && x.pointer == y.pointer - - case Type_Info_Relative_Multi_Pointer: - y := b.variant.(Type_Info_Relative_Multi_Pointer) or_return - return x.base_integer == y.base_integer && x.pointer == y.pointer case Type_Info_Matrix: y := b.variant.(Type_Info_Matrix) or_return @@ -392,18 +384,6 @@ is_simd_vector :: proc(info: ^Type_Info) -> bool { _, ok := type_info_base(info).variant.(Type_Info_Simd_Vector) return ok } -@(require_results) -is_relative_pointer :: proc(info: ^Type_Info) -> bool { - if info == nil { return false } - _, ok := type_info_base(info).variant.(Type_Info_Relative_Pointer) - return ok -} -@(require_results) -is_relative_multi_pointer :: proc(info: ^Type_Info) -> bool { - if info == nil { return false } - _, ok := type_info_base(info).variant.(Type_Info_Relative_Multi_Pointer) - return ok -} @(require_results) @@ -736,18 +716,6 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt io.write_i64(w, i64(info.count), 10, &n) or_return io.write_byte(w, ']', &n) or_return write_type(w, info.elem, &n) or_return - - case Type_Info_Relative_Pointer: - io.write_string(w, "#relative(", &n) or_return - write_type(w, info.base_integer, &n) or_return - io.write_string(w, ") ", &n) or_return - write_type(w, info.pointer, &n) or_return - - case Type_Info_Relative_Multi_Pointer: - io.write_string(w, "#relative(", &n) or_return - write_type(w, info.base_integer, &n) or_return - io.write_string(w, ") ", &n) or_return - write_type(w, info.pointer, &n) or_return case Type_Info_Matrix: if info.layout == .Row_Major { diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index b234ba4f3..36d1359ca 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -2052,22 +2052,6 @@ explicit_context_definition :: proc "c" () { dummy_procedure() } -relative_data_types :: proc() { - fmt.println("\n#relative data types") - - x: int = 123 - ptr: #relative(i16) ^int - ptr = &x - fmt.println(ptr^) - - arr := [3]int{1, 2, 3} - multi_ptr: #relative(i16) [^]int - multi_ptr = &arr[0] - fmt.println(multi_ptr) - fmt.println(multi_ptr[:3]) - fmt.println(multi_ptr[1]) -} - or_else_operator :: proc() { fmt.println("\n#'or_else'") { @@ -2634,7 +2618,6 @@ main :: proc() { constant_literal_expressions() union_maybe() explicit_context_definition() - relative_data_types() or_else_operator() or_return_operator() or_break_and_or_continue_operators() diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 05f491690..cb4647f33 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -897,20 +897,6 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand } } - if (is_type_relative_pointer(dst)) { - i64 score = check_distance_between_types(c, operand, dst->RelativePointer.pointer_type, allow_array_programming); - if (score >= 0) { - return score+2; - } - } - - if (is_type_relative_multi_pointer(dst)) { - i64 score = check_distance_between_types(c, operand, dst->RelativeMultiPointer.pointer_type, allow_array_programming); - if (score >= 0) { - return score+2; - } - } - if (is_type_proc(dst)) { if (are_types_identical(src, dst)) { return 3; @@ -1052,12 +1038,6 @@ gb_internal AstPackage *get_package_of_type(Type *type) { case Type_DynamicArray: type = type->DynamicArray.elem; continue; - case Type_RelativePointer: - type = type->RelativePointer.pointer_type; - continue; - case Type_RelativeMultiPointer: - type = type->RelativeMultiPointer.pointer_type; - continue; } return nullptr; } @@ -8230,17 +8210,6 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 } return true; - case Type_RelativeMultiPointer: - { - Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type); - GB_ASSERT(pointer_type->kind == Type_MultiPointer); - o->type = pointer_type->MultiPointer.elem; - if (o->mode != Addressing_Constant) { - o->mode = Addressing_Variable; - } - } - return true; - case Type_DynamicArray: o->type = t->DynamicArray.elem; if (o->mode != Addressing_Constant) { @@ -10623,8 +10592,6 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, // Okay } else if (is_type_string(t)) { // Okay - } else if (is_type_relative_multi_pointer(t)) { - // Okay } else if (is_type_matrix(t)) { // Okay } else { @@ -10779,11 +10746,6 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, } break; - case Type_RelativeMultiPointer: - valid = true; - o->type = type_deref(o->type); - break; - case Type_EnumeratedArray: { gbString str = expr_to_string(o->expr); @@ -10860,16 +10822,6 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, x[i:n] -> []T */ o->type = alloc_type_slice(t->MultiPointer.elem); - } else if (t->kind == Type_RelativeMultiPointer && se->high != nullptr) { - /* - x[:] -> [^]T - x[i:] -> [^]T - x[:n] -> []T - x[i:n] -> []T - */ - Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type); - GB_ASSERT(pointer_type->kind == Type_MultiPointer); - o->type = alloc_type_slice(pointer_type->MultiPointer.elem); } @@ -11230,22 +11182,6 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast } else if (t->kind == Type_SoaPointer) { o->mode = Addressing_SoaVariable; o->type = type_deref(t); - } else if (t->kind == Type_RelativePointer) { - if (o->mode != Addressing_Variable) { - gbString str = expr_to_string(o->expr); - gbString typ = type_to_string(o->type); - error(o->expr, "Cannot dereference relative pointer '%s' of type '%s' as it does not have a variable addressing mode", str, typ); - gb_string_free(typ); - gb_string_free(str); - } - - // NOTE(bill): This is required because when dereferencing, the original type has been lost - add_type_info_type(c, o->type); - - Type *ptr_type = base_type(t->RelativePointer.pointer_type); - GB_ASSERT(ptr_type->kind == Type_Pointer); - o->mode = Addressing_Variable; - o->type = ptr_type->Pointer.elem; } else { gbString str = expr_to_string(o->expr); gbString typ = type_to_string(o->type); diff --git a/src/check_type.cpp b/src/check_type.cpp index bbeff9ca7..84e7fb249 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -3517,41 +3517,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T case_end; case_ast_node(rt, RelativeType, e); - GB_ASSERT(rt->tag->kind == Ast_CallExpr); - ast_node(ce, CallExpr, rt->tag); - - Type *base_integer = nullptr; - - if (ce->args.count != 1) { - error(rt->type, "#relative expected 1 type argument, got %td", ce->args.count); - } else { - base_integer = check_type(ctx, ce->args[0]); - if (!is_type_integer(base_integer)) { - error(rt->type, "#relative base types must be an integer"); - base_integer = nullptr; - } else if (type_size_of(base_integer) > 64) { - error(rt->type, "#relative base integer types be less than or equal to 64-bits"); - base_integer = nullptr; - } - } - - Type *relative_type = nullptr; - Type *base_type = check_type(ctx, rt->type); - if (!is_type_pointer(base_type) && !is_type_multi_pointer(base_type)) { - error(rt->type, "#relative types can only be a pointer or multi-pointer"); - relative_type = base_type; - } else if (base_integer == nullptr) { - relative_type = base_type; - } else { - if (is_type_pointer(base_type)) { - relative_type = alloc_type_relative_pointer(base_type, base_integer); - } else if (is_type_multi_pointer(base_type)) { - relative_type = alloc_type_relative_multi_pointer(base_type, base_integer); - } - } - GB_ASSERT(relative_type != nullptr); - - *type = relative_type; + error(e, "#relative types have been removed from the compiler. Prefer \"core:relative\"."); + *type = t_invalid; set_base_type(named_type, *type); return true; case_end; diff --git a/src/checker.cpp b/src/checker.cpp index 76f996648..b7cf343f8 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2186,16 +2186,6 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { add_type_info_type_internal(c, bt->SimdVector.elem); break; - case Type_RelativePointer: - add_type_info_type_internal(c, bt->RelativePointer.pointer_type); - add_type_info_type_internal(c, bt->RelativePointer.base_integer); - break; - - case Type_RelativeMultiPointer: - add_type_info_type_internal(c, bt->RelativeMultiPointer.pointer_type); - add_type_info_type_internal(c, bt->RelativeMultiPointer.base_integer); - break; - case Type_Matrix: add_type_info_type_internal(c, bt->Matrix.elem); break; @@ -2441,16 +2431,6 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, bt->SimdVector.elem); break; - case Type_RelativePointer: - add_min_dep_type_info(c, bt->RelativePointer.pointer_type); - add_min_dep_type_info(c, bt->RelativePointer.base_integer); - break; - - case Type_RelativeMultiPointer: - add_min_dep_type_info(c, bt->RelativeMultiPointer.pointer_type); - add_min_dep_type_info(c, bt->RelativeMultiPointer.base_integer); - break; - case Type_Matrix: add_min_dep_type_info(c, bt->Matrix.elem); break; @@ -3075,8 +3055,6 @@ gb_internal void init_core_type_info(Checker *c) { t_type_info_map = find_core_type(c, str_lit("Type_Info_Map")); t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set")); t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector")); - t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer")); - t_type_info_relative_multi_pointer = find_core_type(c, str_lit("Type_Info_Relative_Multi_Pointer")); t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix")); t_type_info_soa_pointer = find_core_type(c, str_lit("Type_Info_Soa_Pointer")); t_type_info_bit_field = find_core_type(c, str_lit("Type_Info_Bit_Field")); @@ -3105,8 +3083,6 @@ gb_internal void init_core_type_info(Checker *c) { t_type_info_map_ptr = alloc_type_pointer(t_type_info_map); t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set); t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector); - t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer); - t_type_info_relative_multi_pointer_ptr = alloc_type_pointer(t_type_info_relative_multi_pointer); t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix); t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer); t_type_info_bit_field_ptr = alloc_type_pointer(t_type_info_bit_field); diff --git a/src/docs_format.cpp b/src/docs_format.cpp index ca6ecb5c2..6378971d0 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -79,8 +79,7 @@ enum OdinDocTypeKind : u32 { OdinDocType_SOAStructFixed = 17, OdinDocType_SOAStructSlice = 18, OdinDocType_SOAStructDynamic = 19, - OdinDocType_RelativePointer = 20, - OdinDocType_RelativeMultiPointer = 21, + OdinDocType_MultiPointer = 22, OdinDocType_Matrix = 23, OdinDocType_SoaPointer = 24, diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 835dfdff1..341b3fa6b 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -776,24 +776,6 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { doc_type.types = odin_doc_type_as_slice(w, type->SimdVector.elem); // TODO(bill): break; - case Type_RelativePointer: - doc_type.kind = OdinDocType_RelativePointer; - { - OdinDocTypeIndex types[2] = {}; - types[0] = odin_doc_type(w, type->RelativePointer.pointer_type); - types[1] = odin_doc_type(w, type->RelativePointer.base_integer); - doc_type.types = odin_write_slice(w, types, gb_count_of(types)); - } - break; - case Type_RelativeMultiPointer: - doc_type.kind = OdinDocType_RelativeMultiPointer; - { - OdinDocTypeIndex types[2] = {}; - types[0] = odin_doc_type(w, type->RelativeMultiPointer.pointer_type); - types[1] = odin_doc_type(w, type->RelativeMultiPointer.base_integer); - doc_type.types = odin_write_slice(w, types, gb_count_of(types)); - } - break; case Type_Matrix: doc_type.kind = OdinDocType_Matrix; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 68f95cb03..464efa325 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -75,7 +75,6 @@ enum lbAddrKind { lbAddr_Context, lbAddr_SoaVariable, - lbAddr_RelativePointer, lbAddr_Swizzle, lbAddr_SwizzleLarge, @@ -103,9 +102,6 @@ struct lbAddr { lbValue index; Ast *node; } index_set; - struct { - bool deref; - } relative; struct { Type *type; u8 count; // 2, 3, or 4 components diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 5cc79dcc8..464f7065c 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -920,17 +920,6 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { elem, subscripts, gb_count_of(subscripts)); } - case Type_RelativePointer: { - LLVMMetadataRef base_integer = lb_debug_type(m, type->RelativePointer.base_integer); - gbString name = type_to_string(type, temporary_allocator()); - return LLVMDIBuilderCreateTypedef(m->debug_builder, base_integer, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type))); - } - case Type_RelativeMultiPointer: { - LLVMMetadataRef base_integer = lb_debug_type(m, type->RelativeMultiPointer.base_integer); - gbString name = type_to_string(type, temporary_allocator()); - return LLVMDIBuilderCreateTypedef(m->debug_builder, base_integer, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type))); - } - case Type_Matrix: { LLVMMetadataRef subscripts[1] = {}; subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder, diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 8ad44035d..80c469ae6 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4200,30 +4200,6 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { return lb_addr(v); } - case Type_RelativeMultiPointer: { - lbAddr rel_ptr_addr = {}; - if (deref) { - lbValue rel_ptr_ptr = lb_build_expr(p, ie->expr); - rel_ptr_addr = lb_addr(rel_ptr_ptr); - } else { - rel_ptr_addr = lb_build_addr(p, ie->expr); - } - lbValue rel_ptr = lb_relative_pointer_to_pointer(p, rel_ptr_addr); - - lbValue index = lb_build_expr(p, ie->index); - index = lb_emit_conv(p, index, t_int); - lbValue v = {}; - - Type *pointer_type = base_type(t->RelativeMultiPointer.pointer_type); - GB_ASSERT(pointer_type->kind == Type_MultiPointer); - Type *elem = pointer_type->MultiPointer.elem; - - LLVMValueRef indices[1] = {index.value}; - v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, elem), rel_ptr.value, indices, 1, ""); - v.type = alloc_type_pointer(elem); - return lb_addr(v); - } - case Type_DynamicArray: { lbValue dynamic_array = {}; dynamic_array = lb_build_expr(p, ie->expr); @@ -4333,13 +4309,6 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { return slice; } - case Type_RelativePointer: - GB_PANIC("TODO(bill): Type_RelativePointer should be handled above already on the lb_addr_load"); - break; - case Type_RelativeMultiPointer: - GB_PANIC("TODO(bill): Type_RelativeMultiPointer should be handled above already on the lb_addr_load"); - break; - case Type_DynamicArray: { Type *elem_type = type->DynamicArray.elem; Type *slice_type = alloc_type_slice(elem_type); @@ -5343,11 +5312,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_ast_node(de, DerefExpr, expr); Type *t = type_of_expr(de->expr); - if (is_type_relative_pointer(t)) { - lbAddr addr = lb_build_addr(p, de->expr); - addr.relative.deref = true; - return addr; - } else if (is_type_soa_pointer(t)) { + if (is_type_soa_pointer(t)) { lbValue value = lb_build_expr(p, de->expr); lbValue ptr = lb_emit_struct_ev(p, value, 0); lbValue idx = lb_emit_struct_ev(p, value, 1); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 686724f6a..9dc603993 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -409,14 +409,6 @@ gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) { gb_internal lbAddr lb_addr(lbValue addr) { lbAddr v = {lbAddr_Default, addr}; - if (addr.type != nullptr && is_type_relative_pointer(type_deref(addr.type))) { - GB_ASSERT(is_type_pointer(addr.type)); - v.kind = lbAddr_RelativePointer; - } else if (addr.type != nullptr && is_type_relative_multi_pointer(type_deref(addr.type))) { - GB_ASSERT(is_type_pointer(addr.type) || - is_type_multi_pointer(addr.type)); - v.kind = lbAddr_RelativePointer; - } return v; } @@ -501,42 +493,6 @@ gb_internal Type *lb_addr_type(lbAddr const &addr) { return type_deref(addr.addr.type); } - -gb_internal lbValue lb_relative_pointer_to_pointer(lbProcedure *p, lbAddr const &addr) { - GB_ASSERT(addr.kind == lbAddr_RelativePointer); - - Type *t = base_type(lb_addr_type(addr)); - GB_ASSERT(is_type_relative_pointer(t) || is_type_relative_multi_pointer(t)); - - Type *pointer_type = nullptr; - Type *base_integer = nullptr; - if (t->kind == Type_RelativePointer) { - pointer_type = t->RelativePointer.pointer_type; - base_integer = t->RelativePointer.base_integer; - } else if (t->kind == Type_RelativeMultiPointer) { - pointer_type = t->RelativeMultiPointer.pointer_type; - base_integer = t->RelativeMultiPointer.base_integer; - } - - lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr); - lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(base_integer)); - offset = lb_emit_load(p, offset); - - if (!is_type_unsigned(base_integer)) { - offset = lb_emit_conv(p, offset, t_i64); - } - offset = lb_emit_conv(p, offset, t_uintptr); - lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr); - absolute_ptr = lb_emit_conv(p, absolute_ptr, pointer_type); - - lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, base_integer)); - - // NOTE(bill): nil check - lbValue nil_ptr = lb_const_nil(p->module, pointer_type); - lbValue final_ptr = lb_emit_select(p, cond, nil_ptr, absolute_ptr); - return final_ptr; -} - gb_internal lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue const &addr, lbValue const &index) { lbAddr v = lb_add_local_generated(p, type, false); lbValue ptr = lb_emit_struct_ep(p, v.addr, 0); @@ -557,9 +513,6 @@ gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { case lbAddr_Map: return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key); - case lbAddr_RelativePointer: - return lb_relative_pointer_to_pointer(p, addr); - case lbAddr_SoaVariable: { Type *soa_ptr_type = alloc_type_soa_pointer(lb_addr_type(addr)); @@ -584,9 +537,6 @@ gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { gb_internal lbValue lb_build_addr_ptr(lbProcedure *p, Ast *expr) { lbAddr addr = lb_build_addr(p, expr); - if (addr.kind == lbAddr_RelativePointer) { - return addr.addr; - } return lb_addr_get_ptr(p, addr); } @@ -819,10 +769,6 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { value.value = LLVMConstNull(lb_type(p->module, t)); } - if (addr.kind == lbAddr_RelativePointer && addr.relative.deref) { - addr = lb_addr(lb_address_from_load(p, lb_addr_load(p, addr))); - } - if (addr.kind == lbAddr_BitField) { lbValue dst = addr.addr; if (is_type_endian_big(addr.bitfield.type)) { @@ -860,44 +806,6 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { lb_emit_runtime_call(p, "__write_bits", args); } return; - } else if (addr.kind == lbAddr_RelativePointer) { - Type *rel_ptr = base_type(lb_addr_type(addr)); - GB_ASSERT(rel_ptr->kind == Type_RelativePointer || - rel_ptr->kind == Type_RelativeMultiPointer); - Type *pointer_type = nullptr; - Type *base_integer = nullptr; - - if (rel_ptr->kind == Type_RelativePointer) { - pointer_type = rel_ptr->RelativePointer.pointer_type; - base_integer = rel_ptr->RelativePointer.base_integer; - } else if (rel_ptr->kind == Type_RelativeMultiPointer) { - pointer_type = rel_ptr->RelativeMultiPointer.pointer_type; - base_integer = rel_ptr->RelativeMultiPointer.base_integer; - } - - value = lb_emit_conv(p, value, pointer_type); - - GB_ASSERT(is_type_pointer(addr.addr.type)); - lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr); - lbValue val_ptr = lb_emit_conv(p, value, t_uintptr); - lbValue offset = {}; - offset.value = LLVMBuildSub(p->builder, val_ptr.value, ptr.value, ""); - offset.type = t_uintptr; - - if (!is_type_unsigned(base_integer)) { - offset = lb_emit_conv(p, offset, t_i64); - } - offset = lb_emit_conv(p, offset, base_integer); - - lbValue offset_ptr = lb_emit_conv(p, addr.addr, alloc_type_pointer(base_integer)); - offset = lb_emit_select(p, - lb_emit_comp(p, Token_CmpEq, val_ptr, lb_const_nil(p->module, t_uintptr)), - lb_const_nil(p->module, base_integer), - offset - ); - LLVMBuildStore(p->builder, offset.value, offset_ptr.value); - return; - } else if (addr.kind == lbAddr_Map) { lb_internal_dynamic_map_set(p, addr.addr, addr.map.type, addr.map.key, value, p->curr_stmt); return; @@ -1246,46 +1154,6 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { } return r; - } else if (addr.kind == lbAddr_RelativePointer) { - Type *rel_ptr = base_type(lb_addr_type(addr)); - Type *base_integer = nullptr; - Type *pointer_type = nullptr; - GB_ASSERT(rel_ptr->kind == Type_RelativePointer || - rel_ptr->kind == Type_RelativeMultiPointer); - - if (rel_ptr->kind == Type_RelativePointer) { - base_integer = rel_ptr->RelativePointer.base_integer; - pointer_type = rel_ptr->RelativePointer.pointer_type; - } else if (rel_ptr->kind == Type_RelativeMultiPointer) { - base_integer = rel_ptr->RelativeMultiPointer.base_integer; - pointer_type = rel_ptr->RelativeMultiPointer.pointer_type; - } - - lbValue ptr = lb_emit_conv(p, addr.addr, t_uintptr); - lbValue offset = lb_emit_conv(p, ptr, alloc_type_pointer(base_integer)); - offset = lb_emit_load(p, offset); - - - if (!is_type_unsigned(base_integer)) { - offset = lb_emit_conv(p, offset, t_i64); - } - offset = lb_emit_conv(p, offset, t_uintptr); - lbValue absolute_ptr = lb_emit_arith(p, Token_Add, ptr, offset, t_uintptr); - absolute_ptr = lb_emit_conv(p, absolute_ptr, pointer_type); - - lbValue cond = lb_emit_comp(p, Token_CmpEq, offset, lb_const_nil(p->module, base_integer)); - - // NOTE(bill): nil check - lbValue nil_ptr = lb_const_nil(p->module, pointer_type); - lbValue final_ptr = {}; - final_ptr.type = absolute_ptr.type; - final_ptr.value = LLVMBuildSelect(p->builder, cond.value, nil_ptr.value, absolute_ptr.value, ""); - - if (rel_ptr->kind == Type_RelativeMultiPointer) { - return final_ptr; - } - return lb_emit_load(p, final_ptr); - } else if (addr.kind == lbAddr_Map) { Type *map_type = base_type(type_deref(addr.addr.type)); GB_ASSERT(map_type->kind == Type_Map); @@ -2378,13 +2246,6 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Type_SimdVector: return LLVMVectorType(lb_type(m, type->SimdVector.elem), cast(unsigned)type->SimdVector.count); - - case Type_RelativePointer: - return lb_type_internal(m, type->RelativePointer.base_integer); - case Type_RelativeMultiPointer: - return lb_type_internal(m, type->RelativeMultiPointer.base_integer); - - case Type_Matrix: { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index f3fcc8de4..6c12b37be 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -61,8 +61,6 @@ gb_internal u64 lb_typeid_kind(lbModule *m, Type *type, u64 id=0) { case Type_Proc: kind = Typeid_Procedure; break; case Type_BitSet: kind = Typeid_Bit_Set; break; case Type_SimdVector: kind = Typeid_Simd_Vector; break; - case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; - case Type_RelativeMultiPointer: kind = Typeid_Relative_Multi_Pointer; break; case Type_SoaPointer: kind = Typeid_SoaPointer; break; case Type_BitField: kind = Typeid_Bit_Field; break; } @@ -950,30 +948,6 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ } break; - case Type_RelativePointer: - { - tag_type = t_type_info_relative_pointer; - LLVMValueRef vals[2] = { - get_type_info_ptr(m, t->RelativePointer.pointer_type), - get_type_info_ptr(m, t->RelativePointer.base_integer), - }; - - variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); - } - break; - - case Type_RelativeMultiPointer: - { - tag_type = t_type_info_relative_multi_pointer; - LLVMValueRef vals[2] = { - get_type_info_ptr(m, t->RelativeMultiPointer.pointer_type), - get_type_info_ptr(m, t->RelativeMultiPointer.base_integer), - }; - - variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); - } - break; - case Type_Matrix: { tag_type = t_type_info_matrix; diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index e6049da84..a2a0ba4cc 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1131,10 +1131,6 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { Type *t = base_type(type_deref(s.type)); Type *result_type = nullptr; - if (is_type_relative_pointer(t)) { - s = lb_addr_get_ptr(p, lb_addr(s)); - } - if (is_type_struct(t)) { result_type = get_struct_field_type(t, index); } else if (is_type_union(t)) { @@ -1440,8 +1436,6 @@ gb_internal lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection e = lb_emit_array_epi(p, e, index); } else if (type->kind == Type_Map) { e = lb_emit_struct_ep(p, e, index); - } else if (type->kind == Type_RelativePointer) { - e = lb_emit_struct_ep(p, e, index); } else { GB_PANIC("un-gep-able type %s", type_to_string(type)); } diff --git a/src/types.cpp b/src/types.cpp index b49bce7d4..c51df7261 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -272,14 +272,6 @@ struct TypeProc { Type *elem; \ Type *generic_count; \ }) \ - TYPE_KIND(RelativePointer, struct { \ - Type *pointer_type; \ - Type *base_integer; \ - }) \ - TYPE_KIND(RelativeMultiPointer, struct { \ - Type *pointer_type; \ - Type *base_integer; \ - }) \ TYPE_KIND(Matrix, struct { \ Type *elem; \ i64 row_count; \ @@ -367,8 +359,6 @@ enum Typeid_Kind : u8 { Typeid_Map, Typeid_Bit_Set, Typeid_Simd_Vector, - Typeid_Relative_Pointer, - Typeid_Relative_Multi_Pointer, Typeid_Matrix, Typeid_SoaPointer, Typeid_Bit_Field, @@ -678,8 +668,6 @@ gb_global Type *t_type_info_enum = nullptr; gb_global Type *t_type_info_map = nullptr; gb_global Type *t_type_info_bit_set = nullptr; gb_global Type *t_type_info_simd_vector = nullptr; -gb_global Type *t_type_info_relative_pointer = nullptr; -gb_global Type *t_type_info_relative_multi_pointer = nullptr; gb_global Type *t_type_info_matrix = nullptr; gb_global Type *t_type_info_soa_pointer = nullptr; gb_global Type *t_type_info_bit_field = nullptr; @@ -708,8 +696,6 @@ gb_global Type *t_type_info_enum_ptr = nullptr; gb_global Type *t_type_info_map_ptr = nullptr; gb_global Type *t_type_info_bit_set_ptr = nullptr; gb_global Type *t_type_info_simd_vector_ptr = nullptr; -gb_global Type *t_type_info_relative_pointer_ptr = nullptr; -gb_global Type *t_type_info_relative_multi_pointer_ptr = nullptr; gb_global Type *t_type_info_matrix_ptr = nullptr; gb_global Type *t_type_info_soa_pointer_ptr = nullptr; gb_global Type *t_type_info_bit_field_ptr = nullptr; @@ -1118,24 +1104,6 @@ gb_internal Type *alloc_type_bit_field() { return t; } -gb_internal Type *alloc_type_relative_pointer(Type *pointer_type, Type *base_integer) { - GB_ASSERT(is_type_pointer(pointer_type)); - GB_ASSERT(is_type_integer(base_integer)); - Type *t = alloc_type(Type_RelativePointer); - t->RelativePointer.pointer_type = pointer_type; - t->RelativePointer.base_integer = base_integer; - return t; -} - -gb_internal Type *alloc_type_relative_multi_pointer(Type *pointer_type, Type *base_integer) { - GB_ASSERT(is_type_multi_pointer(pointer_type)); - GB_ASSERT(is_type_integer(base_integer)); - Type *t = alloc_type(Type_RelativeMultiPointer); - t->RelativeMultiPointer.pointer_type = pointer_type; - t->RelativeMultiPointer.base_integer = base_integer; - return t; -} - gb_internal Type *alloc_type_named(String name, Type *base, Entity *type_name) { Type *t = alloc_type(Type_Named); t->Named.name = name; @@ -1227,8 +1195,6 @@ gb_internal Type *type_deref(Type *t, bool allow_multi_pointer) { switch (bt->kind) { case Type_Pointer: return bt->Pointer.elem; - case Type_RelativePointer: - return type_deref(bt->RelativePointer.pointer_type); case Type_SoaPointer: { Type *elem = base_type(bt->SoaPointer.elem); @@ -1667,15 +1633,6 @@ gb_internal bool is_type_generic(Type *t) { return t->kind == Type_Generic; } -gb_internal bool is_type_relative_pointer(Type *t) { - t = base_type(t); - return t->kind == Type_RelativePointer; -} -gb_internal bool is_type_relative_multi_pointer(Type *t) { - t = base_type(t); - return t->kind == Type_RelativeMultiPointer; -} - gb_internal bool is_type_u8_slice(Type *t) { t = base_type(t); if (t->kind == Type_Slice) { @@ -2118,8 +2075,6 @@ gb_internal bool is_type_indexable(Type *t) { return true; case Type_EnumeratedArray: return true; - case Type_RelativeMultiPointer: - return true; case Type_Matrix: return true; } @@ -2137,8 +2092,6 @@ gb_internal bool is_type_sliceable(Type *t) { return true; case Type_EnumeratedArray: return false; - case Type_RelativeMultiPointer: - return true; case Type_Matrix: return false; } @@ -2345,27 +2298,7 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) { return true; } break; - - case Type_RelativeMultiPointer: - if (is_type_polymorphic(t->RelativeMultiPointer.pointer_type, or_specialized)) { - return true; - } - if (t->RelativeMultiPointer.base_integer != nullptr && - is_type_polymorphic(t->RelativeMultiPointer.base_integer, or_specialized)) { - return true; - } - break; - case Type_RelativePointer: - if (is_type_polymorphic(t->RelativePointer.pointer_type, or_specialized)) { - return true; - } - if (t->RelativePointer.base_integer != nullptr && - is_type_polymorphic(t->RelativePointer.base_integer, or_specialized)) { - return true; - } - break; } - return false; } @@ -2407,10 +2340,6 @@ gb_internal bool type_has_nil(Type *t) { } } return false; - - case Type_RelativePointer: - case Type_RelativeMultiPointer: - return true; } return false; } @@ -2579,10 +2508,6 @@ gb_internal bool is_type_load_safe(Type *type) { } return true; - case Type_RelativePointer: - case Type_RelativeMultiPointer: - return true; - case Type_Pointer: case Type_MultiPointer: case Type_Slice: @@ -3945,11 +3870,6 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { case Type_Matrix: return matrix_align_of(t, path); - case Type_RelativePointer: - return type_align_of_internal(t->RelativePointer.base_integer, path); - case Type_RelativeMultiPointer: - return type_align_of_internal(t->RelativeMultiPointer.base_integer, path); - case Type_SoaPointer: return build_context.int_size; } @@ -4242,11 +4162,6 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { case Type_BitField: return type_size_of_internal(t->BitField.backing_type, path); - - case Type_RelativePointer: - return type_size_of_internal(t->RelativePointer.base_integer, path); - case Type_RelativeMultiPointer: - return type_size_of_internal(t->RelativeMultiPointer.base_integer, path); } // Catch all @@ -4872,19 +4787,6 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_append_fmt(str, "#simd[%d]", cast(int)type->SimdVector.count); str = write_type_to_string(str, type->SimdVector.elem); break; - - case Type_RelativePointer: - str = gb_string_append_fmt(str, "#relative("); - str = write_type_to_string(str, type->RelativePointer.base_integer); - str = gb_string_append_fmt(str, ") "); - str = write_type_to_string(str, type->RelativePointer.pointer_type); - break; - case Type_RelativeMultiPointer: - str = gb_string_append_fmt(str, "#relative("); - str = write_type_to_string(str, type->RelativePointer.base_integer); - str = gb_string_append_fmt(str, ") "); - str = write_type_to_string(str, type->RelativePointer.pointer_type); - break; case Type_Matrix: if (type->Matrix.is_row_major) { -- cgit v1.2.3 From 83bf0c6ab82ed035f3ba133de3411f6e01c1f8d4 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 21 Nov 2024 19:18:17 +0100 Subject: checker: only error with -vet-cast when it is actually castable --- src/check_expr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cb4647f33..53d407b51 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3541,6 +3541,8 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type return false; } + Operand src = *o; + Type *src_t = o->type; Type *dst_t = t; Type *src_bt = base_type(src_t); @@ -3629,7 +3631,8 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type // identical casts that cannot be foreseen or otherwise // forbidden, so just skip them. if (forbid_identical && check_vet_flags(c) & VetFlag_Cast && - (c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig))) { + (c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig)) && + check_is_castable_to(c, &src, dst_t)) { if (are_types_identical(src_t, dst_t)) { gbString oper_str = expr_to_string(o->expr); gbString to_type = type_to_string(dst_t); -- cgit v1.2.3 From 6d83755e9239ea7e4fb6a24d91c9bd8f4148213b Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Thu, 28 Nov 2024 20:44:57 +0100 Subject: Fix assert when return value expected. --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 53d407b51..dd0820fee 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4454,8 +4454,8 @@ gb_internal ExactValue convert_exact_value_for_type(ExactValue v, Type *type) { } gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { - GB_ASSERT_NOT_NULL(target_type); - if (operand->mode == Addressing_Invalid || + // GB_ASSERT_NOT_NULL(target_type); + if (target_type == nullptr || operand->mode == Addressing_Invalid || operand->mode == Addressing_Type || is_type_typed(operand->type) || target_type == t_invalid) { -- cgit v1.2.3 From 65de0256ce173b92ff90c9ea9629aeadc9bb8538 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 2 Dec 2024 15:57:08 +0000 Subject: Fix #4535 --- src/check_expr.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index dd0820fee..cc9483187 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4980,8 +4980,12 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v if (success_) *success_ = true; if (finish_) *finish_ = false; return tav.value; + } else if (is_type_proc(tav.type)) { + if (success_) *success_ = true; + if (finish_) *finish_ = false; + return tav.value; } else { - GB_ASSERT(is_type_untyped_nil(tav.type)); + GB_ASSERT_MSG(is_type_untyped_nil(tav.type), "%s", type_to_string(tav.type)); if (success_) *success_ = true; if (finish_) *finish_ = false; return tav.value; -- cgit v1.2.3 From 14216ebf5169581a738e9c235ef8119a95271b12 Mon Sep 17 00:00:00 2001 From: Barinzaya Date: Thu, 19 Dec 2024 20:07:04 -0500 Subject: Added some implicit broadcasting for #simd arrays. This covers broadcasting from untyped numbers when assigning, as well as when performing binary operations. SIMD intrinsics have not been adjusted --- src/check_expr.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cc9483187..81e33a8e8 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3672,6 +3672,13 @@ gb_internal bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x } } } + if (is_type_simd_vector(x->type) && !is_type_simd_vector(y->type)) { + if (check_is_assignable_to(c, y, x->type)) { + if (check_binary_op(c, x, op)) { + return true; + } + } + } return false; } @@ -4556,6 +4563,19 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar break; } + case Type_SimdVector: { + Type *elem = base_array_type(t); + if (check_is_assignable_to(c, operand, elem)) { + operand->mode = Addressing_Value; + } else { + operand->mode = Addressing_Invalid; + convert_untyped_error(c, operand, target_type); + return; + } + + break; + } + case Type_Matrix: { Type *elem = base_array_type(t); if (check_is_assignable_to(c, operand, elem)) { -- cgit v1.2.3 From 7b334d2bd9e881b450fb19e394d6d71840a62cf9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 1 Jan 2025 17:26:15 +0000 Subject: Add `#branch_location` --- src/check_expr.cpp | 12 +++++++ src/entity.cpp | 1 + src/llvm_backend.hpp | 7 +++- src/llvm_backend_expr.cpp | 12 +++++-- src/llvm_backend_proc.cpp | 6 +++- src/llvm_backend_stmt.cpp | 81 ++++++++++++++++++++++++++++---------------- src/llvm_backend_utility.cpp | 8 ++--- 7 files changed, 89 insertions(+), 38 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cc9483187..fba9b8dad 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8725,6 +8725,18 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A error(node, "#caller_expression may only be used as a default argument parameter"); o->type = t_string; o->mode = Addressing_Value; + } else if (name == "branch_location") { + if (!c->in_defer) { + error(node, "#branch_location may only be used within a 'defer' statement"); + } else if (c->curr_proc_decl) { + Entity *e = c->curr_proc_decl->entity; + if (e != nullptr) { + GB_ASSERT(e->kind == Entity_Procedure); + e->Procedure.uses_branch_location = true; + } + } + o->type = t_source_code_location; + o->mode = Addressing_Value; } else { if (name == "location") { init_core_source_code_location(c->checker); diff --git a/src/entity.cpp b/src/entity.cpp index 0c4a20df4..802b381f9 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -256,6 +256,7 @@ struct Entity { bool entry_point_only : 1; bool has_instrumentation : 1; bool is_memcpy_like : 1; + bool uses_branch_location : 1; } Procedure; struct { Array entities; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index e84ffd1cd..8ca11bf28 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -359,6 +359,10 @@ struct lbProcedure { bool in_multi_assignment; Array raw_input_parameters; + bool uses_branch_location; + TokenPos branch_location_pos; + TokenPos curr_token_pos; + Array variadic_reuses; lbAddr variadic_reuse_base_array_ptr; @@ -444,7 +448,8 @@ gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isiz gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type); gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type); -gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block); +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos); +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node); gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t); gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right); gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining = ProcInlining_none); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 9c325e088..3b238bcd8 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3502,7 +3502,13 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { case_ast_node(bd, BasicDirective, expr); TokenPos pos = bd->token.pos; - GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(bd->name.string)); + String name = bd->name.string; + if (name == "branch_location") { + GB_ASSERT(p->uses_branch_location); + String proc_name = p->entity->token.string; + return lb_emit_source_code_location_as_global(p, proc_name, p->branch_location_pos); + } + GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(name)); case_end; case_ast_node(i, Implicit, expr); @@ -3668,7 +3674,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); lb_start_block(p, else_); - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr); lb_emit_jump(p, block); lb_start_block(p, then); @@ -5493,7 +5499,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); lb_start_block(p, else_); - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, expr); lb_emit_jump(p, block); lb_start_block(p, then); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 712e13592..7e44a0046 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -125,6 +125,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i // map_init(&p->selector_addr, 0); // map_init(&p->tuple_fix_map, 0); + if (p->entity != nullptr && p->entity->Procedure.uses_branch_location) { + p->uses_branch_location = true; + } + if (p->is_foreign) { lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); } @@ -757,7 +761,7 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) { if (p->type->Proc.result_count == 0) { instr = LLVMGetLastInstruction(p->curr_block->block); if (!lb_is_instr_terminating(instr)) { - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, p->body); lb_set_debug_position_to_procedure_end(p); LLVMBuildRetVoid(p->builder); } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 9a5f25712..a2f0d2f4a 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -208,8 +208,8 @@ gb_internal void lb_open_scope(lbProcedure *p, Scope *s) { } -gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) { - lb_emit_defer_stmts(p, kind, block); +gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node, bool pop_stack=true) { + lb_emit_defer_stmts(p, kind, block, node); GB_ASSERT(p->scope_index > 0); // NOTE(bill): Remove `context`s made in that scope @@ -721,7 +721,7 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node->left); lb_pop_target_list(p); if (check != nullptr) { @@ -854,7 +854,7 @@ gb_internal void lb_build_range_tuple(lbProcedure *p, AstRangeStmt *rs, Scope *s lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -976,7 +976,7 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -1192,7 +1192,7 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc lb_build_stmt(p, rs->body); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); lb_pop_target_list(p); lb_emit_jump(p, loop); lb_start_block(p, done); @@ -1363,7 +1363,7 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * } - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, rs->body); } gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) { @@ -1433,6 +1433,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * ast_node(body, BlockStmt, ss->body); isize case_count = body->stmts.count; + Ast *default_clause = nullptr; Slice default_stmts = {}; lbBlock *default_fall = nullptr; lbBlock *default_block = nullptr; @@ -1482,6 +1483,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * if (cc->list.count == 0) { // default case + default_clause = clause; default_stmts = cc->stmts; default_fall = fall; if (switch_instr == nullptr) { @@ -1552,7 +1554,7 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * lb_push_target_list(p, ss->label, done, nullptr, fall); lb_open_scope(p, body->scope); lb_build_stmt_list(p, cc->stmts); - lb_close_scope(p, lbDeferExit_Default, body); + lb_close_scope(p, lbDeferExit_Default, body, clause); lb_pop_target_list(p); lb_emit_jump(p, done); @@ -1570,13 +1572,13 @@ gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope * lb_push_target_list(p, ss->label, done, nullptr, default_fall); lb_open_scope(p, default_block->scope); lb_build_stmt_list(p, default_stmts); - lb_close_scope(p, lbDeferExit_Default, default_block); + lb_close_scope(p, lbDeferExit_Default, default_block, default_clause); lb_pop_target_list(p); } lb_emit_jump(p, done); lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, done); + lb_close_scope(p, lbDeferExit_Default, done, ss->body); } gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value, bool is_default_case) { @@ -1627,7 +1629,7 @@ gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBl lb_push_target_list(p, label, done, nullptr, nullptr); lb_build_stmt_list(p, cc->stmts); - lb_close_scope(p, lbDeferExit_Default, body); + lb_close_scope(p, lbDeferExit_Default, body, clause); lb_pop_target_list(p); lb_emit_jump(p, done); @@ -1835,7 +1837,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss lb_emit_jump(p, done); lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, done); + lb_close_scope(p, lbDeferExit_Default, done, ss->body); } @@ -1959,7 +1961,7 @@ gb_internal void lb_build_assignment(lbProcedure *p, Array &lvals, Slice p->in_multi_assignment = prev_in_assignment; } -gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { +gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos) { lbFunctionType *ft = lb_get_function_type(p->module, p->type); bool return_by_pointer = ft->ret.kind == lbArg_Indirect; bool split_returns = ft->multiple_return_original_type != nullptr; @@ -1982,7 +1984,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value); } - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2012,7 +2014,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { ret_val = OdinLLVMBuildTransmute(p, ret_val, ret_type); } - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2021,7 +2023,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { } } } -gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results) { +gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results, TokenPos pos) { lb_ensure_abi_function_type(p->module, p); isize return_count = p->type->Proc.result_count; @@ -2029,7 +2031,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return if (return_count == 0) { // No return values - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); // Check for terminator in the defer stmts LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); @@ -2138,11 +2140,11 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return GB_ASSERT(result_values.count-1 == result_eps.count); lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]); - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); LLVMBuildRetVoid(p->builder); return; } else { - return lb_build_return_stmt_internal(p, result_values[result_values.count-1]); + return lb_build_return_stmt_internal(p, result_values[result_values.count-1], pos); } } else { @@ -2169,7 +2171,7 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return } if (return_by_pointer) { - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr, pos); LLVMBuildRetVoid(p->builder); return; } @@ -2177,13 +2179,13 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return res = lb_emit_load(p, res); } } - lb_build_return_stmt_internal(p, res); + lb_build_return_stmt_internal(p, res, pos); } gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { ast_node(is, IfStmt, node); lb_open_scope(p, is->scope); // Scope #1 - defer (lb_close_scope(p, lbDeferExit_Default, nullptr)); + defer (lb_close_scope(p, lbDeferExit_Default, nullptr, node)); lbBlock *then = lb_create_block(p, "if.then"); lbBlock *done = lb_create_block(p, "if.done"); @@ -2234,7 +2236,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, scope_of_node(is->else_stmt)); lb_build_stmt(p, is->else_stmt); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt); } lb_emit_jump(p, done); @@ -2251,7 +2253,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, scope_of_node(is->else_stmt)); lb_build_stmt(p, is->else_stmt); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, is->else_stmt); lb_emit_jump(p, done); } @@ -2322,7 +2324,7 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) { } lb_start_block(p, done); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node); } gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) { @@ -2588,7 +2590,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { lb_open_scope(p, bs->scope); lb_build_stmt_list(p, bs->stmts); - lb_close_scope(p, lbDeferExit_Default, nullptr); + lb_close_scope(p, lbDeferExit_Default, nullptr, node); if (done != nullptr) { lb_emit_jump(p, done); @@ -2702,7 +2704,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { case_end; case_ast_node(rs, ReturnStmt, node); - lb_build_return_stmt(p, rs->results); + lb_build_return_stmt(p, rs->results, ast_token(node).pos); case_end; case_ast_node(is, IfStmt, node); @@ -2755,7 +2757,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { } } if (block != nullptr) { - lb_emit_defer_stmts(p, lbDeferExit_Branch, block); + lb_emit_defer_stmts(p, lbDeferExit_Branch, block, node); } lb_emit_jump(p, block); lb_start_block(p, lb_create_block(p, "unreachable")); @@ -2795,7 +2797,13 @@ gb_internal void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) { } } -gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) { +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, TokenPos pos) { + TokenPos prev_token_pos = p->branch_location_pos; + if (p->uses_branch_location) { + p->branch_location_pos = pos; + } + defer (p->branch_location_pos = prev_token_pos); + isize count = p->defer_stmts.count; isize i = count; while (i --> 0) { @@ -2822,6 +2830,21 @@ gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlo } } +gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node) { + TokenPos pos = {}; + if (node) { + if (node->kind == Ast_BlockStmt) { + pos = ast_end_token(node).pos; + } else if (node->kind == Ast_CaseClause) { + pos = ast_end_token(node).pos; + } else { + pos = ast_token(node).pos; + } + } + return lb_emit_defer_stmts(p, kind, block, pos); +} + + gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) { Type *pt = base_type(p->type); GB_ASSERT(pt->kind == Type_Proc); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index a2a0ba4cc..3e4393a8f 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -476,8 +476,8 @@ gb_internal lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, Ty } } -gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results); -gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res); +gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results, TokenPos pos); +gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res, TokenPos pos); gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) { lbValue lhs = {}; @@ -506,10 +506,10 @@ gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue con lbValue found = map_must_get(&p->module->values, end_entity); lb_emit_store(p, found, rhs); - lb_build_return_stmt(p, {}); + lb_build_return_stmt(p, {}, ast_token(arg).pos); } else { GB_ASSERT(tuple->variables.count == 1); - lb_build_return_stmt_internal(p, rhs); + lb_build_return_stmt_internal(p, rhs, ast_token(arg).pos); } } lb_start_block(p, continue_block); -- cgit v1.2.3 From 2efe4c2d68f486006e405ba7d30be03ec121ae6c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 13:19:10 +0000 Subject: Add `#+feature dynamic-literals` --- src/build_settings.cpp | 12 +++++++++ src/check_expr.cpp | 10 ++++++-- src/parser.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/parser.hpp | 2 ++ 4 files changed, 88 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 4c3f4b782..a8261612e 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -324,6 +324,18 @@ u64 get_vet_flag_from_name(String const &name) { return VetFlag_NONE; } +enum OptInFeatureFlags : u64 { + OptInFeatureFlag_NONE = 0, + OptInFeatureFlag_DynamicLiterals = 1u<<0, +}; + +u64 get_feature_flag_from_name(String const &name) { + if (name == "dynamic-literals") { + return OptInFeatureFlag_DynamicLiterals; + } + return OptInFeatureFlag_NONE; +} + enum SanitizerFlags : u32 { SanitizerFlag_NONE = 0, diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fba9b8dad..fb3040e71 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9730,8 +9730,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (t->kind == Type_DynamicArray) { - if (build_context.no_dynamic_literals && cl->elems.count) { + if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { + ERROR_BLOCK(); error(node, "Compound literals of dynamic types have been disabled"); + error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); + error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); } } @@ -10120,8 +10123,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } } - if (build_context.no_dynamic_literals && cl->elems.count) { + if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { + ERROR_BLOCK(); error(node, "Compound literals of dynamic types have been disabled"); + error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); + error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); } else { add_map_reserve_dependencies(c); add_map_set_dependencies(c); diff --git a/src/parser.cpp b/src/parser.cpp index aa90651d3..01ed46ebc 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6265,10 +6265,16 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { syntax_error(token_for_pos, "Invalid vet flag name: %.*s", LIT(p)); error_line("\tExpected one of the following\n"); error_line("\tunused\n"); + error_line("\tunused-variables\n"); + error_line("\tunused-imports\n"); + error_line("\tunused-procedures\n"); error_line("\tshadowing\n"); error_line("\tusing-stmt\n"); error_line("\tusing-param\n"); + error_line("\tstyle\n"); error_line("\textra\n"); + error_line("\tcast\n"); + error_line("\ttabs\n"); return build_context.vet_flags; } } @@ -6286,6 +6292,63 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { return vet_flags &~ vet_not_flags; } +gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { + String const prefix = str_lit("feature"); + GB_ASSERT(string_starts_with(s, prefix)); + s = string_trim_whitespace(substring(s, prefix.len, s.len)); + + if (s.len == 0) { + return OptInFeatureFlag_NONE; + } + + u64 feature_flags = 0; + u64 feature_not_flags = 0; + + while (s.len > 0) { + String p = string_trim_whitespace(vet_tag_get_token(s, &s)); + if (p.len == 0) { + break; + } + + bool is_notted = false; + if (p[0] == '!') { + is_notted = true; + p = substring(p, 1, p.len); + if (p.len == 0) { + syntax_error(token_for_pos, "Expected a feature flag name after '!'"); + return OptInFeatureFlag_NONE; + } + } + + u64 flag = get_vet_flag_from_name(p); + if (flag != OptInFeatureFlag_NONE) { + if (is_notted) { + feature_not_flags |= flag; + } else { + feature_flags |= flag; + } + } else { + ERROR_BLOCK(); + syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p)); + error_line("\tExpected one of the following\n"); + error_line("\tdynamic-literals\n"); + return OptInFeatureFlag_NONE; + } + } + + if (feature_flags == 0 && feature_not_flags == 0) { + return OptInFeatureFlag_NONE; + } + if (feature_flags == 0 && feature_not_flags != 0) { + return OptInFeatureFlag_NONE &~ feature_not_flags; + } + if (feature_flags != 0 && feature_not_flags == 0) { + return feature_flags; + } + GB_ASSERT(feature_flags != 0 && feature_not_flags != 0); + return feature_flags &~ feature_not_flags; +} + gb_internal String dir_from_path(String path) { String base_dir = path; for (isize i = path.len-1; i >= 0; i--) { @@ -6409,6 +6472,9 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } } else if (lc == "no-instrumentation") { f->flags |= AstFile_NoInstrumentation; + } else if (string_starts_with(lc, str_lit("feature"))) { + f->feature_flags = parse_feature_tag(tok, lc); + f->feature_flags_set = true; } else { error(tok, "Unknown tag '%.*s'", LIT(lc)); } diff --git a/src/parser.hpp b/src/parser.hpp index e332fed50..bbf70d03e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -108,7 +108,9 @@ struct AstFile { String package_name; u64 vet_flags; + u64 feature_flags; bool vet_flags_set; + bool feature_flags_set; // >= 0: In Expression // < 0: In Control Clause -- cgit v1.2.3 From bca08d3b85f59c35f4eb43731099bc96730b12cd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 5 Jan 2025 13:22:27 +0000 Subject: Make `-no-dynamic-literals` the default now --- examples/demo/demo.odin | 1 + src/build_settings.cpp | 6 ------ src/check_expr.cpp | 37 +++++++++++++++++++++---------------- src/checker.cpp | 18 +++++++++++++++++- src/llvm_backend.cpp | 2 -- src/llvm_backend_expr.cpp | 4 ++-- src/main.cpp | 2 +- src/parser.cpp | 4 ++-- 8 files changed, 44 insertions(+), 30 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 36d1359ca..82b047103 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -1,4 +1,5 @@ #+vet !using-stmt !using-param +#+feature dynamic-literals package main import "core:fmt" diff --git a/src/build_settings.cpp b/src/build_settings.cpp index a8261612e..93168cf77 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -441,7 +441,6 @@ struct BuildContext { bool ignore_unknown_attributes; bool no_bounds_check; bool no_type_assert; - bool no_dynamic_literals; bool no_output_files; bool no_crt; bool no_rpath; @@ -1867,11 +1866,6 @@ gb_internal bool init_build_paths(String init_filename) { produces_output_file = true; } - if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR || - build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) { - bc->no_dynamic_literals = true; - } - if (!produces_output_file) { // Command doesn't produce output files. We're done. return true; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fb3040e71..ba021a98c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9351,6 +9351,23 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) { return false; } +gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) { + if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0) { + ERROR_BLOCK(); + error(node, "Compound literals of dynamic types are disabled by default"); + error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n"); + error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); + if (build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR) { + error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n"); + } else if (build_context.ODIN_DEFAULT_TO_PANIC_ALLOCATOR) { + error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n"); + } + return false; + } + + return cl->elems.count > 0; +} + gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; ast_node(cl, CompoundLit, node); @@ -9551,11 +9568,6 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * elem_type = t->DynamicArray.elem; context_name = str_lit("dynamic array literal"); is_constant = false; - - if (!build_context.no_dynamic_literals) { - add_package_dependency(c, "runtime", "__dynamic_array_reserve"); - add_package_dependency(c, "runtime", "__dynamic_array_append"); - } } else if (t->kind == Type_SimdVector) { elem_type = t->SimdVector.elem; context_name = str_lit("simd vector literal"); @@ -9730,11 +9742,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (t->kind == Type_DynamicArray) { - if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { - ERROR_BLOCK(); - error(node, "Compound literals of dynamic types have been disabled"); - error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); - error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); + if (check_for_dynamic_literals(c, node, cl)) { + add_package_dependency(c, "runtime", "__dynamic_array_reserve"); + add_package_dependency(c, "runtime", "__dynamic_array_append"); } } @@ -10123,12 +10133,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } } - if (build_context.no_dynamic_literals && cl->elems.count && (node->file()->feature_flags & OptInFeatureFlag_DynamicLiterals) != 0) { - ERROR_BLOCK(); - error(node, "Compound literals of dynamic types have been disabled"); - error_line("\tSuggestion: If you want to enable them for this specific file, use '#+feature dynamic-literals' at the top of the file\n"); - error_line("\tWarning: Please understand that dynamic literals will implicitly allocate using the current 'context.allocator' in that scope\n"); - } else { + if (check_for_dynamic_literals(c, node, cl)) { add_map_reserve_dependencies(c); add_map_set_dependencies(c); } diff --git a/src/checker.cpp b/src/checker.cpp index 7e0a64d75..5d3263789 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -542,6 +542,23 @@ gb_internal u64 check_vet_flags(Ast *node) { return ast_file_vet_flags(file); } +gb_internal u64 check_feature_flags(CheckerContext *c, Ast *node) { + AstFile *file = c->file; + if (file == nullptr && + c->curr_proc_decl && + c->curr_proc_decl->proc_lit) { + file = c->curr_proc_decl->proc_lit->file(); + } + if (file == nullptr) { + file = node->file(); + } + if (file != nullptr && file->feature_flags_set) { + return file->feature_flags; + } + return 0; +} + + enum VettedEntityKind { VettedEntity_Invalid, @@ -1164,7 +1181,6 @@ gb_internal void init_universal(void) { add_global_bool_constant("ODIN_NO_BOUNDS_CHECK", build_context.no_bounds_check); add_global_bool_constant("ODIN_NO_TYPE_ASSERT", build_context.no_type_assert); add_global_bool_constant("ODIN_DEFAULT_TO_PANIC_ALLOCATOR", bc->ODIN_DEFAULT_TO_PANIC_ALLOCATOR); - add_global_bool_constant("ODIN_NO_DYNAMIC_LITERALS", bc->no_dynamic_literals); add_global_bool_constant("ODIN_NO_CRT", bc->no_crt); add_global_bool_constant("ODIN_USE_SEPARATE_MODULES", bc->use_separate_modules); add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 01ded321e..696ced0df 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1096,8 +1096,6 @@ gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_ } gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) { - GB_ASSERT(!build_context.no_dynamic_literals); - TEMPORARY_ALLOCATOR_GUARD(); String proc_name = {}; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 3b238bcd8..df9dca801 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4813,7 +4813,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(!build_context.no_dynamic_literals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals); lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); gb_unused(err); @@ -4902,7 +4902,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(!build_context.no_dynamic_literals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals); Type *et = bt->DynamicArray.elem; lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); diff --git a/src/main.cpp b/src/main.cpp index 0450c61ec..41c7170f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1192,7 +1192,7 @@ gb_internal bool parse_build_flags(Array args) { build_context.no_type_assert = true; break; case BuildFlag_NoDynamicLiterals: - build_context.no_dynamic_literals = true; + gb_printf_err("Warning: Use of -no-dynamic-literals is now redundant\n"); break; case BuildFlag_NoCRT: build_context.no_crt = true; diff --git a/src/parser.cpp b/src/parser.cpp index 01ed46ebc..e190bc5a5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6320,7 +6320,7 @@ gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { } } - u64 flag = get_vet_flag_from_name(p); + u64 flag = get_feature_flag_from_name(p); if (flag != OptInFeatureFlag_NONE) { if (is_notted) { feature_not_flags |= flag; @@ -6473,7 +6473,7 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } else if (lc == "no-instrumentation") { f->flags |= AstFile_NoInstrumentation; } else if (string_starts_with(lc, str_lit("feature"))) { - f->feature_flags = parse_feature_tag(tok, lc); + f->feature_flags |= parse_feature_tag(tok, lc); f->feature_flags_set = true; } else { error(tok, "Unknown tag '%.*s'", LIT(lc)); -- cgit v1.2.3