From 5f2b220a850c6812bb7b5e4d778be37d8dc8962b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 25 Jul 2022 12:12:25 +0100 Subject: Fix minor issue with a lack of a trailing comma --- src/parser.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index 247255ce8..b62ec7a74 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3894,7 +3894,8 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi while (f->curr_token.kind != follow && - f->curr_token.kind != Token_EOF) { + f->curr_token.kind != Token_EOF && + f->curr_token.kind != Token_Semicolon) { CommentGroup *docs = f->lead_comment; u32 set_flags = parse_field_prefixes(f); Token tag = {}; @@ -3922,7 +3923,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi default_value = parse_expr(f, false); if (!allow_default_parameters) { syntax_error(f->curr_token, "Default parameters are only allowed for procedures"); - default_value = nullptr; + default_value = nullptr; } } -- cgit v1.2.3 From c9c3611b1d4aa5e570addf7a8632dab503e2dbea Mon Sep 17 00:00:00 2001 From: Phil Date: Mon, 25 Jul 2022 15:46:47 -0700 Subject: remove leftover print statement --- src/llvm_backend_const.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 24b2bc3a2..201932ad9 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1041,7 +1041,6 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc i64 v = big_int_to_i64(&tav.value.value_integer); i64 lower = type->BitSet.lower; u64 index = cast(u64)(v-lower); - gb_printf_err("index: %llu\n", index); BigInt bit = {}; big_int_from_u64(&bit, index); big_int_shl(&bit, &one, &bit); -- cgit v1.2.3 From b1ae5bc9fef7f8729765f90d32bd6e18e99dea71 Mon Sep 17 00:00:00 2001 From: Jorri Fransen Date: Thu, 28 Jul 2022 15:28:26 +0200 Subject: Changed param count from 2 to 1 for simd_abs. --- src/checker_builtin_procs.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 05f256775..3ea6fcdd5 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -434,7 +434,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_neg"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, - {STR_LIT("simd_abs"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_abs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_min"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_max"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From b886ae6515440da18dec7292c43e09835170a632 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 1 Aug 2022 15:32:17 +0100 Subject: Simplify parser logic for field prefixes --- src/parser.cpp | 53 +++++++++++++++++++---------------------------------- src/parser.hpp | 4 ++++ 2 files changed, 23 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index b62ec7a74..934b5afcd 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3550,49 +3550,34 @@ Ast *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_typeid_token) { } -enum FieldPrefixKind : i32 { - FieldPrefix_Unknown = -1, - FieldPrefix_Invalid = 0, - - FieldPrefix_using, // implies #subtype - FieldPrefix_const, - FieldPrefix_no_alias, - FieldPrefix_c_vararg, - FieldPrefix_auto_cast, - FieldPrefix_any_int, - FieldPrefix_subtype, // does not imply `using` semantics - FieldPrefix_by_ptr, -}; - struct ParseFieldPrefixMapping { String name; TokenKind token_kind; - FieldPrefixKind prefix; FieldFlag flag; }; gb_global ParseFieldPrefixMapping parse_field_prefix_mappings[] = { - {str_lit("using"), Token_using, FieldPrefix_using, FieldFlag_using}, - {str_lit("auto_cast"), Token_auto_cast, FieldPrefix_auto_cast, FieldFlag_auto_cast}, - {str_lit("no_alias"), Token_Hash, FieldPrefix_no_alias, FieldFlag_no_alias}, - {str_lit("c_vararg"), Token_Hash, FieldPrefix_c_vararg, FieldFlag_c_vararg}, - {str_lit("const"), Token_Hash, FieldPrefix_const, FieldFlag_const}, - {str_lit("any_int"), Token_Hash, FieldPrefix_any_int, FieldFlag_any_int}, - {str_lit("subtype"), Token_Hash, FieldPrefix_subtype, FieldFlag_subtype}, - {str_lit("by_ptr"), Token_Hash, FieldPrefix_by_ptr, FieldFlag_by_ptr}, + {str_lit("using"), Token_using, FieldFlag_using}, + {str_lit("auto_cast"), Token_auto_cast, FieldFlag_auto_cast}, + {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}, }; -FieldPrefixKind is_token_field_prefix(AstFile *f) { +FieldFlag is_token_field_prefix(AstFile *f) { switch (f->curr_token.kind) { case Token_EOF: - return FieldPrefix_Invalid; + return FieldFlag_Invalid; case Token_using: - return FieldPrefix_using; + return FieldFlag_using; case Token_auto_cast: - return FieldPrefix_auto_cast; + return FieldFlag_auto_cast; case Token_Hash: advance_token(f); @@ -3602,33 +3587,33 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) { auto const &mapping = parse_field_prefix_mappings[i]; if (mapping.token_kind == Token_Hash) { if (f->curr_token.string == mapping.name) { - return mapping.prefix; + return mapping.flag; } } } break; } - return FieldPrefix_Unknown; + return FieldFlag_Unknown; } - return FieldPrefix_Invalid; + return FieldFlag_Invalid; } u32 parse_field_prefixes(AstFile *f) { i32 counts[gb_count_of(parse_field_prefix_mappings)] = {}; for (;;) { - FieldPrefixKind kind = is_token_field_prefix(f); - if (kind == FieldPrefix_Invalid) { + FieldFlag flag = is_token_field_prefix(f); + if (flag & FieldFlag_Invalid) { break; } - if (kind == FieldPrefix_Unknown) { + if (flag & FieldFlag_Unknown) { syntax_error(f->curr_token, "Unknown prefix kind '#%.*s'", LIT(f->curr_token.string)); advance_token(f); continue; } for (i32 i = 0; i < gb_count_of(parse_field_prefix_mappings); i++) { - if (parse_field_prefix_mappings[i].prefix == kind) { + if (parse_field_prefix_mappings[i].flag == flag) { counts[i] += 1; advance_token(f); break; diff --git a/src/parser.hpp b/src/parser.hpp index 3126e0a02..862ef0f77 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -308,6 +308,10 @@ enum FieldFlag : u32 { FieldFlag_Tags = 1<<10, FieldFlag_Results = 1<<16, + + FieldFlag_Unknown = 1u<<30, + FieldFlag_Invalid = 1u<<31, + // Parameter List Restrictions FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr, FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags, -- cgit v1.2.3 From 5168cf03a9c321de464c2709a37607ea9c1edbe8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 1 Aug 2022 15:38:50 +0100 Subject: Remove dead `#maybe` code --- core/odin/parser/parser.odin | 13 +------------ src/check_type.cpp | 5 ----- src/docs_format.cpp | 1 - src/parser.cpp | 12 +++--------- src/parser.hpp | 1 - 5 files changed, 4 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index dc7c7b759..69f42b8ec 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2595,7 +2595,6 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { tok := expect_token(p, .Union) poly_params: ^ast.Field_List align: ^ast.Expr - is_maybe: bool is_no_nil: bool is_shared_nil: bool @@ -2620,10 +2619,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { } align = parse_expr(p, true) case "maybe": - if is_maybe { - error(p, tag.pos, "duplicate union tag '#%s'", tag.text) - } - is_maybe = true + error(p, tag.pos, "#%s functionality has now been merged with standard 'union' functionality", tag.text) case "no_nil": if is_no_nil { error(p, tag.pos, "duplicate union tag '#%s'", tag.text) @@ -2640,19 +2636,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { } p.expr_level = prev_level - if is_no_nil && is_maybe { - error(p, p.curr_tok.pos, "#maybe and #no_nil cannot be applied together") - } if is_no_nil && is_shared_nil { error(p, p.curr_tok.pos, "#shared_nil and #no_nil cannot be applied together") } - if is_shared_nil && is_maybe { - error(p, p.curr_tok.pos, "#maybe and #shared_nil cannot be applied together") - } union_kind := ast.Union_Type_Kind.Normal switch { - case is_maybe: union_kind = .maybe case is_no_nil: union_kind = .no_nil case is_shared_nil: union_kind = .shared_nil } diff --git a/src/check_type.cpp b/src/check_type.cpp index dea523599..5d37ff208 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -695,11 +695,6 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Arrayalign, "A union with #no_nil must have at least 2 variants"); } break; - case UnionType_maybe: - if (variants.count != 1) { - error(ut->align, "A union with #maybe must have at 1 variant, got %lld", cast(long long)variants.count); - } - break; } if (ut->align != nullptr) { diff --git a/src/docs_format.cpp b/src/docs_format.cpp index ee32d0e05..b1c3c87e7 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -98,7 +98,6 @@ enum OdinDocTypeFlag_Struct : u32 { enum OdinDocTypeFlag_Union : u32 { OdinDocTypeFlag_Union_polymorphic = 1<<0, OdinDocTypeFlag_Union_no_nil = 1<<1, - OdinDocTypeFlag_Union_maybe = 1<<2, OdinDocTypeFlag_Union_shared_nil = 1<<3, }; diff --git a/src/parser.cpp b/src/parser.cpp index 934b5afcd..ac3acef8a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2548,21 +2548,15 @@ Ast *parse_operand(AstFile *f, bool lhs) { syntax_error(tag, "Invalid union tag '#%.*s'", LIT(tag.string)); } } - if (no_nil && maybe) { - syntax_error(f->curr_token, "#maybe and #no_nil cannot be applied together"); - } + if (no_nil && shared_nil) { syntax_error(f->curr_token, "#shared_nil and #no_nil cannot be applied together"); } - if (shared_nil && maybe) { - syntax_error(f->curr_token, "#maybe and #shared_nil cannot be applied together"); - } - if (maybe) { - union_kind = UnionType_maybe; syntax_error(f->curr_token, "#maybe functionality has now been merged with standard 'union' functionality"); - } else if (no_nil) { + } + if (no_nil) { union_kind = UnionType_no_nil; } else if (shared_nil) { union_kind = UnionType_shared_nil; diff --git a/src/parser.hpp b/src/parser.hpp index 862ef0f77..156991e24 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -339,7 +339,6 @@ char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = { enum UnionTypeKind : u8 { UnionType_Normal = 0, - UnionType_maybe = 1, // removed UnionType_no_nil = 2, UnionType_shared_nil = 3, }; -- cgit v1.2.3 From 483a72ac61f6e67ac7077a9b5d715ea23e933d22 Mon Sep 17 00:00:00 2001 From: Ian Lilley Date: Wed, 3 Aug 2022 12:34:03 -0400 Subject: fixed debug symbols for range interval --- src/llvm_backend_stmt.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index f131bb3db..8f5120946 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -458,15 +458,6 @@ void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, val1_type = type_of_expr(rs->vals[1]); } - if (val0_type != nullptr) { - Entity *e = entity_of_node(rs->vals[0]); - lb_add_local(p, e->type, e, true); - } - if (val1_type != nullptr) { - Entity *e = entity_of_node(rs->vals[1]); - lb_add_local(p, e->type, e, true); - } - TokenKind op = Token_Lt; switch (node->op.kind) { case Token_Ellipsis: op = Token_LtEq; break; @@ -478,10 +469,22 @@ void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lbValue lower = lb_build_expr(p, node->left); lbValue upper = {}; // initialized each time in the loop - lbAddr value = lb_add_local_generated(p, val0_type ? val0_type : lower.type, false); + lbAddr value; + if (val0_type != nullptr) { + Entity *e = entity_of_node(rs->vals[0]); + value = lb_add_local(p, val0_type ? val0_type : lower.type, e, false); + } else { + value = lb_add_local_generated(p, val0_type ? val0_type : lower.type, false); + } lb_addr_store(p, value, lower); - lbAddr index = lb_add_local_generated(p, t_int, false); + lbAddr index; + if (val1_type != nullptr) { + Entity *e = entity_of_node(rs->vals[1]); + index = lb_add_local(p, t_int, e, false); + } else { + index = lb_add_local_generated(p, t_int, false); + } lb_addr_store(p, index, lb_const_int(m, t_int, 0)); lbBlock *loop = lb_create_block(p, "for.interval.loop"); -- cgit v1.2.3 From 6caab6225da912be51cbce5e6498490e6dcba06b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Aug 2022 11:36:12 +0100 Subject: Fix #1930 --- src/llvm_backend_expr.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index b28470770..07c3224de 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2270,6 +2270,9 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } } + a = core_type(left.type); + b = core_type(right.type); + if (is_type_matrix(a) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { Type *tl = base_type(a); lbValue lhs = lb_address_from_load_or_generate_local(p, left); -- cgit v1.2.3 From 576914aee1565618d8448a2bbc3cbef0c4acc4d1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Aug 2022 11:57:33 +0100 Subject: Make `unreachable()` a built-in compiler-level procedure --- core/runtime/core_builtin.odin | 14 -------------- src/check_builtin.cpp | 1 + src/check_stmt.cpp | 13 ++++++++----- src/checker_builtin_procs.hpp | 6 +++++- src/llvm_backend_proc.cpp | 5 +++++ 5 files changed, 19 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/core/runtime/core_builtin.odin b/core/runtime/core_builtin.odin index e9fc2a91e..3b8a0fab3 100644 --- a/core/runtime/core_builtin.odin +++ b/core/runtime/core_builtin.odin @@ -785,17 +785,3 @@ unimplemented :: proc(message := "", loc := #caller_location) -> ! { } p("not yet implemented", message, loc) } - -@builtin -@(disabled=ODIN_DISABLE_ASSERT) -unreachable :: proc(message := "", loc := #caller_location) -> ! { - p := context.assertion_failure_proc - if p == nil { - p = default_assertion_failure_proc - } - if message != "" { - p("internal error", message, loc) - } else { - p("internal error", "entered unreachable code", loc) - } -} diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8108604ba..8f8f7f9e2 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3569,6 +3569,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 operand->mode = Addressing_NoValue; break; + case BuiltinProc_unreachable: case BuiltinProc_trap: case BuiltinProc_debug_trap: operand->mode = Addressing_NoValue; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index a6f6f1a7d..451325324 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1,8 +1,5 @@ -bool is_diverging_stmt(Ast *stmt) { - if (stmt->kind != Ast_ExprStmt) { - return false; - } - Ast *expr = unparen_expr(stmt->ExprStmt.expr); +bool is_diverging_expr(Ast *expr) { + expr = unparen_expr(expr); if (expr->kind != Ast_CallExpr) { return false; } @@ -26,6 +23,12 @@ bool is_diverging_stmt(Ast *stmt) { t = base_type(t); return t != nullptr && t->kind == Type_Proc && t->Proc.diverging; } +bool is_diverging_stmt(Ast *stmt) { + if (stmt->kind != Ast_ExprStmt) { + return false; + } + return is_diverging_expr(stmt->ExprStmt.expr); +} bool contains_deferred_call(Ast *node) { if (node->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 3ea6fcdd5..8dd021255 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -40,6 +40,8 @@ enum BuiltinProcId { BuiltinProc_hadamard_product, BuiltinProc_matrix_flatten, + BuiltinProc_unreachable, + BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures // "Intrinsics" @@ -330,6 +332,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {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}, + {STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE @@ -341,7 +345,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("alloca"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("cpu_relax"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, - {STR_LIT("trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/true}, + {STR_LIT("trap"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics, /*diverging*/true}, {STR_LIT("debug_trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/false}, {STR_LIT("read_cycle_counter"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 0b0c0794b..a026356a2 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1851,6 +1851,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, return lb_emit_matrix_flatten(p, m, tv.type); } + case BuiltinProc_unreachable: + LLVMBuildUnreachable(p->builder); + return {}; + + // "Intrinsics" case BuiltinProc_alloca: -- cgit v1.2.3 From a58e4d035964275ade5e09fa6bcafb5d46cc46e2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Aug 2022 12:19:57 +0100 Subject: Allow for `foo() or_else unreachable()` and other diverging procedures --- src/check_expr.cpp | 26 +++++++++++++++-- src/llvm_backend_proc.cpp | 2 +- src/llvm_backend_utility.cpp | 69 +++++++++++++++++++++++++++++--------------- 3 files changed, 70 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cf9f2f751..96adde013 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -119,6 +119,7 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint); void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); +bool is_diverging_expr(Ast *expr); void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { auto results = did_you_mean_results(d); @@ -7399,8 +7400,25 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type return Expr_Expr; } - check_multi_expr_with_type_hint(c, &y, default_value, x.type); - error_operand_no_value(&y); + bool y_is_diverging = false; + check_expr_base(c, &y, default_value, x.type); + switch (y.mode) { + case Addressing_NoValue: + if (is_diverging_expr(y.expr)) { + // Allow + y.mode = Addressing_Value; + y_is_diverging = true; + } else { + error_operand_no_value(&y); + y.mode = Addressing_Invalid; + } + break; + case Addressing_Type: + error_operand_not_expression(&y); + y.mode = Addressing_Invalid; + break; + } + if (y.mode == Addressing_Invalid) { o->mode = Addressing_Value; o->type = t_invalid; @@ -7414,7 +7432,9 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value); if (left_type != nullptr) { - check_assignment(c, &y, left_type, name); + if (!y_is_diverging) { + check_assignment(c, &y, left_type, name); + } } else { check_or_else_expr_no_value_error(c, name, x, type_hint); } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index a026356a2..67f008a35 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1852,7 +1852,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } case BuiltinProc_unreachable: - LLVMBuildUnreachable(p->builder); + lb_emit_unreachable(p); return {}; diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 88ec2f22c..bbacce7a2 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -39,6 +39,12 @@ bool lb_is_type_aggregate(Type *t) { return false; } +void lb_emit_unreachable(lbProcedure *p) { + LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); + if (instr == nullptr || !lb_is_instr_terminating(instr)) { + LLVMBuildUnreachable(p->builder); + } +} lbValue lb_correct_endianness(lbProcedure *p, lbValue value) { Type *src = core_type(value.type); @@ -350,40 +356,57 @@ lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue c lbValue rhs = {}; lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs); - LLVMValueRef incoming_values[2] = {}; - LLVMBasicBlockRef incoming_blocks[2] = {}; - GB_ASSERT(else_expr != nullptr); - lbBlock *then = lb_create_block(p, "or_else.then"); - lbBlock *done = lb_create_block(p, "or_else.done"); // NOTE(bill): Append later - lbBlock *else_ = lb_create_block(p, "or_else.else"); - - lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); - lb_start_block(p, then); Type *type = default_type(tv.type); - incoming_values[0] = lb_emit_conv(p, lhs, type).value; + if (is_diverging_expr(else_expr)) { + lbBlock *then = lb_create_block(p, "or_else.then"); + lbBlock *else_ = lb_create_block(p, "or_else.else"); - lb_emit_jump(p, done); - lb_start_block(p, else_); + lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); + // NOTE(bill): else block needs to be straight afterwards to make sure that the actual value is used + // from the then block + lb_start_block(p, else_); - incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, else_expr), type).value; + lb_build_expr(p, else_expr); + lb_emit_unreachable(p); // add just in case - lb_emit_jump(p, done); - lb_start_block(p, done); + lb_start_block(p, then); + return lb_emit_conv(p, lhs, type); + } else { + LLVMValueRef incoming_values[2] = {}; + LLVMBasicBlockRef incoming_blocks[2] = {}; - lbValue res = {}; - res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), ""); - res.type = type; + lbBlock *then = lb_create_block(p, "or_else.then"); + lbBlock *done = lb_create_block(p, "or_else.done"); // NOTE(bill): Append later + lbBlock *else_ = lb_create_block(p, "or_else.else"); - GB_ASSERT(p->curr_block->preds.count >= 2); - incoming_blocks[0] = p->curr_block->preds[0]->block; - incoming_blocks[1] = p->curr_block->preds[1]->block; + lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); + lb_start_block(p, then); - LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2); + incoming_values[0] = lb_emit_conv(p, lhs, type).value; - return res; + lb_emit_jump(p, done); + lb_start_block(p, else_); + + incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, else_expr), type).value; + + lb_emit_jump(p, done); + lb_start_block(p, done); + + lbValue res = {}; + res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), ""); + res.type = type; + + GB_ASSERT(p->curr_block->preds.count >= 2); + incoming_blocks[0] = p->curr_block->preds[0]->block; + incoming_blocks[1] = p->curr_block->preds[1]->block; + + LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2); + + return res; + } } void lb_build_return_stmt(lbProcedure *p, Slice const &return_results); -- cgit v1.2.3 From 9c0a3b6c60d3bc2f64edf0303fafe432853bef60 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 6 Aug 2022 18:37:00 +0200 Subject: Removed use of deprecated functions. Cleaned up most deprecated use of LLVMGetElementType. --- src/llvm_backend.cpp | 11 +-- src/llvm_backend.hpp | 22 ++++- src/llvm_backend_const.cpp | 8 +- src/llvm_backend_expr.cpp | 230 ++++++++++++++++++++++--------------------- src/llvm_backend_general.cpp | 33 +++---- src/llvm_backend_proc.cpp | 203 ++++++++++++++------------------------ src/llvm_backend_type.cpp | 15 ++- src/llvm_backend_utility.cpp | 212 +++++++++++++-------------------------- 8 files changed, 310 insertions(+), 424 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index cf7389ec1..bcd11c8ea 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -739,11 +739,11 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start lb_begin_procedure_body(p); if (startup_type_info) { - LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); + LLVMBuildCall2(p->builder, lb_llvm_get_pointer_type(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); } if (objc_names) { - LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, ""); + LLVMBuildCall2(p->builder, lb_llvm_get_pointer_type(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, ""); } for_array(i, global_variables) { @@ -762,7 +762,7 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start if (init_expr != nullptr) { lbValue init = lb_build_expr(p, init_expr); if (init.value == nullptr) { - LLVMTypeRef global_type = LLVMGetElementType(LLVMTypeOf(var->var.value)); + LLVMTypeRef global_type = llvm_addr_type(p->module, var->var); if (is_type_untyped_undef(init.type)) { // LLVMSetInitializer(var->var.value, LLVMGetUndef(global_type)); LLVMSetInitializer(var->var.value, LLVMConstNull(global_type)); @@ -805,8 +805,7 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr)); lb_emit_store(p, ti, lb_type_info(main_module, var_type)); } else { - LLVMTypeRef pvt = LLVMTypeOf(var->var.value); - LLVMTypeRef vt = LLVMGetElementType(pvt); + LLVMTypeRef vt = llvm_addr_type(p->module, var->var); lbValue src0 = lb_emit_conv(p, var->init, t); LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt); LLVMValueRef dst = var->var.value; @@ -933,7 +932,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) GB_ASSERT(LLVMIsConstant(vals[1])); GB_ASSERT(LLVMIsConstant(vals[2])); - LLVMValueRef dst = LLVMConstInBoundsGEP(all_tests_array.value, indices, gb_count_of(indices)); + LLVMValueRef dst = LLVMConstInBoundsGEP2(llvm_addr_type(m, all_tests_array), all_tests_array.value, indices, gb_count_of(indices)); LLVMValueRef src = llvm_const_named_struct(m, t_Internal_Test, vals, gb_count_of(vals)); LLVMBuildStore(p->builder, src, dst); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index a09286d0b..05dfb3734 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -42,6 +42,18 @@ #define ODIN_LLVM_MINIMUM_VERSION_12 0 #endif +#if LLVM_VERSION_MAJOR > 13 || (LLVM_VERSION_MAJOR == 13 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0) +#define ODIN_LLVM_MINIMUM_VERSION_13 1 +#else +#define ODIN_LLVM_MINIMUM_VERSION_13 0 +#endif + +#if LLVM_VERSION_MAJOR > 14 || (LLVM_VERSION_MAJOR == 14 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0) +#define ODIN_LLVM_MINIMUM_VERSION_14 1 +#else +#define ODIN_LLVM_MINIMUM_VERSION_14 0 +#endif + struct lbProcedure; struct lbValue { @@ -299,7 +311,11 @@ struct lbProcedure { - +#if !ODIN_LLVM_MINIMUM_VERSION_14 +#define LLVMConstGEP2(Ty__, ConstantVal__, ConstantIndices__, NumIndices__) LLVMConstGEP(ConstantVal__, ConstantIndices__, NumIndices__) +#define LLVMConstInBoundsGEP2(Ty__, ConstantVal__, ConstantIndices__, NumIndices__) LLVMConstInBoundsGEP(ConstantVal__, ConstantIndices__, NumIndices__) +#define LLVMBuildPtrDiff2(Builder__, Ty__, LHS__, RHS__, Name__) LLVMBuildPtrDiff(Builder__, LHS__, RHS__, Name__) +#endif bool lb_init_generator(lbGenerator *gen, Checker *c); @@ -327,7 +343,8 @@ lbValue lb_const_int(lbModule *m, Type *type, u64 value); lbAddr lb_addr(lbValue addr); Type *lb_addr_type(lbAddr const &addr); -LLVMTypeRef lb_addr_lb_type(lbAddr const &addr); +LLVMTypeRef lb_llvm_get_pointer_type(LLVMTypeRef type); +LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val); void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value); lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr); lbValue lb_emit_load(lbProcedure *p, lbValue v); @@ -480,6 +497,7 @@ LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align); LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask); +LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count); void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false); void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false); LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 201932ad9..8d910cf24 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -10,7 +10,7 @@ bool lb_is_const(lbValue value) { return false; } - +// TODO remove use of LLVMGetElementType bool lb_is_const_or_global(lbValue value) { if (lb_is_const(value)) { return true; @@ -418,7 +418,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc { LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef ptr = LLVMBuildInBoundsGEP(p->builder, array_data, indices, 2, ""); + LLVMValueRef ptr = LLVMBuildInBoundsGEP2(p->builder, llvm_type, array_data, indices, 2, ""); LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); lbAddr slice = lb_add_local_generated(p, type, false); lb_fill_slice(p, slice, {ptr, alloc_type_pointer(elem)}, {len, t_int}); @@ -445,7 +445,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc { LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef ptr = LLVMConstInBoundsGEP(array_data, indices, 2); + LLVMValueRef ptr = LLVMConstInBoundsGEP2(lb_type(m, t), array_data, indices, 2); LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); LLVMValueRef values[2] = {ptr, len}; @@ -1007,7 +1007,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc for (isize i = 0; i < value_count; i++) { LLVMValueRef val = old_values[i]; if (!LLVMIsConstant(val)) { - LLVMValueRef dst = LLVMBuildStructGEP(p->builder, v.addr.value, cast(unsigned)i, ""); + LLVMValueRef dst = LLVMBuildStructGEP2(p->builder, llvm_addr_type(p->module, v.addr), v.addr.value, cast(unsigned)i, ""); LLVMBuildStore(p->builder, val, dst); } } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 07c3224de..6f8def02c 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -243,8 +243,9 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type) LLVMValueRef v1 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 1, ""), ""); lbAddr addr = lb_add_local_generated(p, x.type, false); - LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP(p->builder, addr.addr.value, 0, "")); - LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP(p->builder, addr.addr.value, 1, "")); + LLVMTypeRef type = llvm_addr_type(p->module, addr.addr); + LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 0, "")); + LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 1, "")); return lb_addr_load(p, addr); } else if (is_type_quaternion(x.type)) { @@ -254,10 +255,11 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type) LLVMValueRef v3 = LLVMBuildFNeg(p->builder, LLVMBuildExtractValue(p->builder, x.value, 3, ""), ""); lbAddr addr = lb_add_local_generated(p, x.type, false); - LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP(p->builder, addr.addr.value, 0, "")); - LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP(p->builder, addr.addr.value, 1, "")); - LLVMBuildStore(p->builder, v2, LLVMBuildStructGEP(p->builder, addr.addr.value, 2, "")); - LLVMBuildStore(p->builder, v3, LLVMBuildStructGEP(p->builder, addr.addr.value, 3, "")); + LLVMTypeRef type = llvm_addr_type(p->module, addr.addr); + LLVMBuildStore(p->builder, v0, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 0, "")); + LLVMBuildStore(p->builder, v1, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 1, "")); + LLVMBuildStore(p->builder, v2, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 2, "")); + LLVMBuildStore(p->builder, v3, LLVMBuildStructGEP2(p->builder, type, addr.addr.value, 3, "")); return lb_addr_load(p, addr); } else if (is_type_simd_vector(x.type)) { Type *elem = base_array_type(x.type); @@ -543,7 +545,7 @@ LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) { #if 1 LLVMValueRef ptr = lb_address_from_load_or_generate_local(p, matrix).value; LLVMValueRef matrix_vector_ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(total_matrix_type, 0), ""); - LLVMValueRef matrix_vector = LLVMBuildLoad(p->builder, matrix_vector_ptr, ""); + LLVMValueRef matrix_vector = LLVMBuildLoad2(p->builder, total_matrix_type, matrix_vector_ptr, ""); LLVMSetAlignment(matrix_vector, cast(unsigned)type_align_of(mt)); return matrix_vector; #else @@ -555,7 +557,7 @@ LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) { LLVMValueRef lb_matrix_trimmed_vector_mask(lbProcedure *p, Type *mt) { mt = base_type(mt); GB_ASSERT(mt->kind == Type_Matrix); - + unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; unsigned column_count = cast(unsigned)mt->Matrix.column_count; @@ -567,23 +569,23 @@ LLVMValueRef lb_matrix_trimmed_vector_mask(lbProcedure *p, Type *mt) { mask_elems[mask_elems_index++] = lb_const_int(p->module, t_u32, offset).value; } } - + LLVMValueRef mask = LLVMConstVector(mask_elems.data, cast(unsigned)mask_elems.count); return mask; } LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) { LLVMValueRef vector = lb_matrix_to_vector(p, m); - + Type *mt = base_type(m.type); GB_ASSERT(mt->kind == Type_Matrix); - + unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; if (stride == row_count) { return vector; } - + LLVMValueRef mask = lb_matrix_trimmed_vector_mask(p, mt); LLVMValueRef trimmed_vector = llvm_basic_shuffle(p, vector, mask); return trimmed_vector; @@ -619,28 +621,28 @@ lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) { } Type *mt = base_type(m.type); GB_ASSERT(mt->kind == Type_Matrix); - + if (lb_is_matrix_simdable(mt)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; unsigned column_count = cast(unsigned)mt->Matrix.column_count; - + auto rows = slice_make(permanent_allocator(), row_count); auto mask_elems = slice_make(permanent_allocator(), column_count); - + LLVMValueRef vector = lb_matrix_to_vector(p, m); for (unsigned i = 0; i < row_count; i++) { for (unsigned j = 0; j < column_count; j++) { unsigned offset = stride*j + i; mask_elems[j] = lb_const_int(p->module, t_u32, offset).value; } - + // transpose mask LLVMValueRef mask = LLVMConstVector(mask_elems.data, column_count); LLVMValueRef row = llvm_basic_shuffle(p, vector, mask); rows[i] = row; } - + lbAddr res = lb_add_local_generated(p, type, true); for_array(i, rows) { LLVMValueRef row = rows[i]; @@ -649,12 +651,12 @@ lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) { ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(LLVMTypeOf(row), 0), ""); LLVMBuildStore(p->builder, row, ptr); } - + return lb_addr_load(p, res); } - + lbAddr res = lb_add_local_generated(p, type, true); - + i64 row_count = mt->Matrix.row_count; i64 column_count = mt->Matrix.column_count; for (i64 j = 0; j < column_count; j++) { @@ -672,10 +674,10 @@ lbValue lb_matrix_cast_vector_to_type(lbProcedure *p, LLVMValueRef vector, Type LLVMValueRef res_ptr = res.addr.value; unsigned alignment = cast(unsigned)gb_max(type_align_of(type), lb_alignof(LLVMTypeOf(vector))); LLVMSetAlignment(res_ptr, alignment); - + res_ptr = LLVMBuildPointerCast(p->builder, res_ptr, LLVMPointerType(LLVMTypeOf(vector), 0), ""); LLVMBuildStore(p->builder, vector, res_ptr); - + return lb_addr_load(p, res); } @@ -687,14 +689,14 @@ lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type) { } Type *mt = base_type(m.type); GB_ASSERT(mt->kind == Type_Matrix); - + if (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; i64 column_count = mt->Matrix.column_count; for (i64 j = 0; j < column_count; j++) { @@ -715,17 +717,17 @@ lbValue lb_emit_outer_product(lbProcedure *p, lbValue a, lbValue b, Type *type) GB_ASSERT(mt->kind == Type_Matrix); GB_ASSERT(at->kind == Type_Array); GB_ASSERT(bt->kind == Type_Array); - - + + i64 row_count = mt->Matrix.row_count; i64 column_count = mt->Matrix.column_count; - + GB_ASSERT(row_count == at->Array.count); GB_ASSERT(column_count == bt->Array.count); - - + + lbAddr res = lb_add_local_generated(p, type, true); - + for (i64 j = 0; j < column_count; j++) { for (i64 i = 0; i < row_count; i++) { lbValue x = lb_emit_struct_ev(p, a, cast(i32)i); @@ -741,51 +743,51 @@ lbValue lb_emit_outer_product(lbProcedure *p, lbValue a, lbValue b, Type *type) lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) { // TODO(bill): Handle edge case for f16 types on x86(-64) platforms - + Type *xt = base_type(lhs.type); Type *yt = base_type(rhs.type); - + GB_ASSERT(is_type_matrix(type)); GB_ASSERT(is_type_matrix(xt)); 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)); - + Type *elem = xt->Matrix.elem; - + unsigned outer_rows = cast(unsigned)xt->Matrix.row_count; unsigned inner = cast(unsigned)xt->Matrix.column_count; unsigned outer_columns = cast(unsigned)yt->Matrix.column_count; - + if (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); - + auto x_rows = slice_make(permanent_allocator(), outer_rows); auto y_columns = slice_make(permanent_allocator(), outer_columns); - + LLVMValueRef x_vector = lb_matrix_to_vector(p, lhs); LLVMValueRef y_vector = lb_matrix_to_vector(p, rhs); - + auto mask_elems = slice_make(permanent_allocator(), inner); for (unsigned i = 0; i < outer_rows; i++) { for (unsigned j = 0; j < inner; j++) { unsigned offset = x_stride*j + i; mask_elems[j] = lb_const_int(p->module, t_u32, offset).value; } - + // transpose mask LLVMValueRef mask = LLVMConstVector(mask_elems.data, inner); LLVMValueRef row = llvm_basic_shuffle(p, x_vector, mask); x_rows[i] = row; } - + for (unsigned i = 0; i < outer_columns; i++) { LLVMValueRef mask = llvm_mask_iota(p->module, y_stride*i, inner); LLVMValueRef column = llvm_basic_shuffle(p, y_vector, mask); y_columns[i] = column; } - + lbAddr res = lb_add_local_generated(p, type, true); for_array(i, x_rows) { LLVMValueRef x_row = x_rows[i]; @@ -795,15 +797,15 @@ lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) lbValue dst = lb_emit_matrix_epi(p, res.addr, i, j); LLVMBuildStore(p->builder, elem, dst.value); } - } + } return lb_addr_load(p, res); } - + { lbAddr res = lb_add_local_generated(p, type, true); - + auto inners = slice_make(permanent_allocator(), inner); - + for (unsigned j = 0; j < outer_columns; j++) { for (unsigned i = 0; i < outer_rows; i++) { lbValue dst = lb_emit_matrix_epi(p, res.addr, i, j); @@ -811,7 +813,7 @@ lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) 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]; @@ -821,51 +823,51 @@ lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) lb_emit_store(p, dst, sum); } } - + return lb_addr_load(p, res); } } lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) { // TODO(bill): Handle edge case for f16 types on x86(-64) platforms - + Type *mt = base_type(lhs.type); Type *vt = base_type(rhs.type); - + GB_ASSERT(is_type_matrix(mt)); GB_ASSERT(is_type_array_like(vt)); - + i64 vector_count = get_array_type_count(vt); - + GB_ASSERT(mt->Matrix.column_count == vector_count); GB_ASSERT(are_types_identical(mt->Matrix.elem, base_array_type(vt))); - + Type *elem = mt->Matrix.elem; - + if (lb_is_matrix_simdable(mt)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); - + unsigned row_count = cast(unsigned)mt->Matrix.row_count; unsigned column_count = cast(unsigned)mt->Matrix.column_count; auto m_columns = slice_make(permanent_allocator(), column_count); auto v_rows = slice_make(permanent_allocator(), column_count); - - LLVMValueRef matrix_vector = lb_matrix_to_vector(p, lhs); - + + LLVMValueRef matrix_vector = lb_matrix_to_vector(p, lhs); + for (unsigned column_index = 0; column_index < column_count; column_index++) { LLVMValueRef mask = llvm_mask_iota(p->module, stride*column_index, row_count); LLVMValueRef column = llvm_basic_shuffle(p, matrix_vector, mask); m_columns[column_index] = column; } - + for (unsigned row_index = 0; row_index < column_count; row_index++) { LLVMValueRef value = lb_emit_struct_ev(p, rhs, row_index).value; LLVMValueRef row = llvm_vector_broadcast(p, value, row_count); v_rows[row_index] = row; } - + GB_ASSERT(column_count > 0); - + LLVMValueRef vector = nullptr; for (i64 i = 0; i < column_count; i++) { if (i == 0) { @@ -874,51 +876,51 @@ lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbValue rhs, Type vector = llvm_vector_mul_add(p, m_columns[i], v_rows[i], vector); } } - + return lb_matrix_cast_vector_to_type(p, vector, type); } - + lbAddr res = lb_add_local_generated(p, type, true); - + for (i64 i = 0; i < mt->Matrix.row_count; i++) { for (i64 j = 0; j < mt->Matrix.column_count; j++) { lbValue dst = lb_emit_matrix_epi(p, res.addr, i, 0); lbValue d0 = lb_emit_load(p, dst); - + lbValue a = lb_emit_matrix_ev(p, lhs, i, j); lbValue b = lb_emit_struct_ev(p, rhs, cast(i32)j); lbValue c = lb_emit_mul_add(p, a, b, d0, elem); lb_emit_store(p, dst, c); } } - + return lb_addr_load(p, res); } lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) { // TODO(bill): Handle edge case for f16 types on x86(-64) platforms - + Type *mt = base_type(rhs.type); Type *vt = base_type(lhs.type); - + GB_ASSERT(is_type_matrix(mt)); GB_ASSERT(is_type_array_like(vt)); - + i64 vector_count = get_array_type_count(vt); - + GB_ASSERT(vector_count == mt->Matrix.row_count); GB_ASSERT(are_types_identical(mt->Matrix.elem, base_array_type(vt))); - + Type *elem = mt->Matrix.elem; - + if (lb_is_matrix_simdable(mt)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); - + unsigned row_count = cast(unsigned)mt->Matrix.row_count; unsigned column_count = cast(unsigned)mt->Matrix.column_count; gb_unused(column_count); auto m_columns = slice_make(permanent_allocator(), row_count); auto v_rows = slice_make(permanent_allocator(), row_count); - + LLVMValueRef matrix_vector = lb_matrix_to_vector(p, rhs); auto mask_elems = slice_make(permanent_allocator(), column_count); @@ -927,21 +929,21 @@ lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type unsigned offset = row_index + column_index*stride; mask_elems[column_index] = lb_const_int(p->module, t_u32, offset).value; } - + // transpose mask LLVMValueRef mask = LLVMConstVector(mask_elems.data, column_count); LLVMValueRef column = llvm_basic_shuffle(p, matrix_vector, mask); m_columns[row_index] = column; } - + for (unsigned column_index = 0; column_index < row_count; column_index++) { LLVMValueRef value = lb_emit_struct_ev(p, lhs, column_index).value; LLVMValueRef row = llvm_vector_broadcast(p, value, column_count); v_rows[column_index] = row; } - + GB_ASSERT(row_count > 0); - + LLVMValueRef vector = nullptr; for (i64 i = 0; i < row_count; i++) { if (i == 0) { @@ -955,27 +957,27 @@ lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type LLVMValueRef res_ptr = res.addr.value; unsigned alignment = cast(unsigned)gb_max(type_align_of(type), lb_alignof(LLVMTypeOf(vector))); LLVMSetAlignment(res_ptr, alignment); - + res_ptr = LLVMBuildPointerCast(p->builder, res_ptr, LLVMPointerType(LLVMTypeOf(vector), 0), ""); LLVMBuildStore(p->builder, vector, res_ptr); - + return lb_addr_load(p, res); } - + lbAddr res = lb_add_local_generated(p, type, true); - + for (i64 j = 0; j < mt->Matrix.column_count; j++) { for (i64 k = 0; k < mt->Matrix.row_count; k++) { lbValue dst = lb_emit_matrix_epi(p, res.addr, 0, j); lbValue d0 = lb_emit_load(p, dst); - + lbValue a = lb_emit_struct_ev(p, lhs, cast(i32)k); lbValue b = lb_emit_matrix_ev(p, rhs, k, j); lbValue c = lb_emit_mul_add(p, a, b, d0, elem); lb_emit_store(p, dst, c); } } - + return lb_addr_load(p, res); } @@ -984,12 +986,12 @@ lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise) { GB_ASSERT(is_type_matrix(lhs.type) || is_type_matrix(rhs.type)); - - + + if (op == Token_Mul && !component_wise) { Type *xt = base_type(lhs.type); Type *yt = base_type(rhs.type); - + if (xt->kind == Type_Matrix) { if (yt->kind == Type_Matrix) { return lb_emit_matrix_mul(p, lhs, rhs, type); @@ -1000,17 +1002,17 @@ lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue GB_ASSERT(yt->kind == Type_Matrix); return lb_emit_vector_mul_matrix(p, lhs, rhs, type); } - + } else { if (is_type_matrix(lhs.type)) { rhs = lb_emit_conv(p, rhs, lhs.type); } else { lhs = lb_emit_conv(p, lhs, rhs.type); } - + Type *xt = base_type(lhs.type); Type *yt = base_type(rhs.type); - + GB_ASSERT_MSG(are_types_identical(xt, yt), "%s %.*s %s", type_to_string(lhs.type), LIT(token_strings[op]), type_to_string(rhs.type)); GB_ASSERT(xt->kind == Type_Matrix); // element-wise arithmetic @@ -1019,8 +1021,8 @@ lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue lbValue array_rhs = rhs; Type *array_type = alloc_type_array(xt->Matrix.elem, matrix_type_total_internal_elems(xt)); GB_ASSERT(type_size_of(array_type) == type_size_of(xt)); - - array_lhs.type = array_type; + + array_lhs.type = array_type; array_rhs.type = array_type; if (token_is_comparison(op)) { @@ -1033,7 +1035,7 @@ lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue } } - + GB_PANIC("TODO: lb_emit_arith_matrix"); return {}; @@ -1314,13 +1316,13 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { ast_node(be, BinaryExpr, expr); TypeAndValue tv = type_and_value_of_expr(expr); - + if (is_type_matrix(be->left->tav.type) || is_type_matrix(be->right->tav.type)) { lbValue left = lb_build_expr(p, be->left); lbValue right = lb_build_expr(p, be->right); return lb_emit_arith_matrix(p, be->op.kind, left, right, default_type(tv.type)); } - + switch (be->op.kind) { case Token_Add: @@ -1690,7 +1692,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } return res; } - + if (is_type_complex(src) && is_type_complex(dst)) { Type *ft = base_complex_elem_type(dst); @@ -1780,7 +1782,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } return lb_emit_conv(p, res, t); } - + if (is_type_integer_128bit(dst)) { auto args = array_make(temporary_allocator(), 1); args[0] = value; @@ -2053,10 +2055,10 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } return lb_addr_load(p, v); } - + if (is_type_matrix(dst) && !is_type_matrix(src)) { GB_ASSERT_MSG(dst->Matrix.row_count == dst->Matrix.column_count, "%s <- %s", type_to_string(dst), type_to_string(src)); - + Type *elem = base_array_type(dst); lbValue e = lb_emit_conv(p, value, elem); lbAddr v = lb_add_local_generated(p, t, false); @@ -2065,16 +2067,16 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { lbValue ptr = lb_emit_matrix_epi(p, v.addr, j, j); lb_emit_store(p, ptr, e); } - - + + return lb_addr_load(p, v); } - + if (is_type_matrix(dst) && is_type_matrix(src)) { GB_ASSERT(dst->kind == Type_Matrix); GB_ASSERT(src->kind == Type_Matrix); lbAddr v = lb_add_local_generated(p, t, true); - + if (is_matrix_square(dst) && is_matrix_square(dst)) { for (i64 j = 0; j < dst->Matrix.column_count; j++) { for (i64 i = 0; i < dst->Matrix.row_count; i++) { @@ -2093,15 +2095,15 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { i64 dst_count = dst->Matrix.row_count*dst->Matrix.column_count; i64 src_count = src->Matrix.row_count*src->Matrix.column_count; GB_ASSERT(dst_count == src_count); - + lbValue pdst = v.addr; lbValue psrc = lb_address_from_load_or_generate_local(p, value); - + bool same_elem_base_types = are_types_identical( base_type(dst->Matrix.elem), base_type(src->Matrix.elem) ); - + if (same_elem_base_types && type_size_of(dst) == type_size_of(src)) { lb_mem_copy_overlapping(p, v.addr, psrc, lb_const_int(p->module, t_int, type_size_of(dst))); } else { @@ -2115,9 +2117,9 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } } return lb_addr_load(p, v); - } - - + } + + if (is_type_any(dst)) { if (is_type_untyped_nil(src)) { @@ -2724,7 +2726,7 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { unsigned indices[2] = {0, 0}; lbValue hashes_data = lb_emit_struct_ep(p, map_ptr, 0); lbValue hashes_data_ptr_ptr = lb_emit_struct_ep(p, hashes_data, 0); - LLVMValueRef hashes_data_ptr = LLVMBuildLoad(p->builder, hashes_data_ptr_ptr.value, ""); + LLVMValueRef hashes_data_ptr = LLVMBuildLoad2(p->builder, llvm_addr_type(p->module, hashes_data_ptr_ptr), hashes_data_ptr_ptr.value, ""); if (op_kind == Token_CmpEq) { res.value = LLVMBuildIsNull(p->builder, hashes_data_ptr, ""); @@ -3325,7 +3327,7 @@ lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { default: GB_PANIC("Unhandled inline asm dialect"); break; } - LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, t)); + LLVMTypeRef func_type = lb_llvm_get_pointer_type(lb_type(p->module, t)); LLVMValueRef the_asm = llvm_get_inline_asm(func_type, asm_string, constraints_string, ia->has_side_effects, ia->has_side_effects, dialect); GB_ASSERT(the_asm != nullptr); return {the_asm, t}; @@ -3791,7 +3793,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { lbValue v = {}; LLVMValueRef indices[1] = {index.value}; - v.value = LLVMBuildGEP(p->builder, multi_ptr.value, indices, 1, ""); + v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, t->MultiPointer.elem), multi_ptr.value, indices, 1, "foo"); v.type = alloc_type_pointer(t->MultiPointer.elem); return lb_addr(v); } @@ -3967,7 +3969,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { if (se->high == nullptr) { lbValue offset = base; LLVMValueRef indices[1] = {low.value}; - offset.value = LLVMBuildGEP(p->builder, offset.value, indices, 1, ""); + offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, ""); lb_addr_store(p, res, offset); } else { low = lb_emit_conv(p, low, t_int); @@ -3976,7 +3978,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); LLVMValueRef indices[1] = {low.value}; - LLVMValueRef ptr = LLVMBuildGEP(p->builder, base.value, indices, 1, ""); + LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, ""); LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, ""); LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b61439238..8dce4c410 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -341,9 +341,6 @@ Type *lb_addr_type(lbAddr const &addr) { } return type_deref(addr.addr.type); } -LLVMTypeRef lb_addr_lb_type(lbAddr const &addr) { - return LLVMGetElementType(LLVMTypeOf(addr.addr.value)); -} lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { if (addr.addr.value == nullptr) { @@ -854,7 +851,7 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { Type *a = type_deref(ptr.type); if (LLVMIsNull(value.value)) { - LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value)); + LLVMTypeRef src_t = llvm_addr_type(p->module, ptr); if (lb_sizeof(src_t) <= lb_max_zero_init_size()) { LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value); } else { @@ -904,8 +901,8 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { } } -LLVMTypeRef llvm_addr_type(lbValue addr_val) { - return LLVMGetElementType(LLVMTypeOf(addr_val.value)); +LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val) { + return lb_type(module, type_deref(addr_val.type)); } lbValue lb_emit_load(lbProcedure *p, lbValue value) { @@ -914,12 +911,12 @@ lbValue lb_emit_load(lbProcedure *p, lbValue value) { Type *vt = base_type(value.type); GB_ASSERT(vt->kind == Type_MultiPointer); Type *t = vt->MultiPointer.elem; - LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); + LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, ""); return lbValue{v, t}; } GB_ASSERT(is_type_pointer(value.type)); Type *t = type_deref(value.type); - LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); + LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, ""); return lbValue{v, t}; } @@ -1184,12 +1181,12 @@ lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) { Type *tag_type = union_tag_type(ut); - LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value)); + LLVMTypeRef uvt = llvm_addr_type(p->module, u); unsigned element_count = LLVMCountStructElementTypes(uvt); GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); lbValue tag_ptr = {}; - tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 1, ""); + tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, u.value, 1, ""); tag_ptr.type = alloc_type_pointer(tag_type); return tag_ptr; } @@ -2006,7 +2003,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { map_set(&m->function_type_map, type, ft); LLVMTypeRef new_abi_fn_ptr_type = lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg); - LLVMTypeRef new_abi_fn_type = LLVMGetElementType(new_abi_fn_ptr_type); + LLVMTypeRef new_abi_fn_type = lb_llvm_get_pointer_type(new_abi_fn_ptr_type); GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx, "\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", @@ -2329,7 +2326,7 @@ general_end:; if (LLVMIsALoadInst(val) && (src_size >= dst_size && src_align >= dst_align)) { LLVMValueRef val_ptr = LLVMGetOperand(val, 0); val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), ""); - LLVMValueRef loaded_val = LLVMBuildLoad(p->builder, val_ptr, ""); + LLVMValueRef loaded_val = LLVMBuildLoad2(p->builder, dst_type, val_ptr, ""); // LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align)); @@ -2345,7 +2342,7 @@ general_end:; LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), ""); LLVMBuildStore(p->builder, val, nptr); - return LLVMBuildLoad(p->builder, ptr, ""); + return LLVMBuildLoad2(p->builder, dst_type, ptr, ""); } } @@ -2371,14 +2368,15 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { isize len = gb_snprintf(name, max_len, "csbs$%x", id); len -= 1; - LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); + LLVMTypeRef type = LLVMTypeOf(data); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); LLVMSetInitializer(global_data, data); LLVMSetLinkage(global_data, LLVMPrivateLinkage); LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr); LLVMSetAlignment(global_data, 1); LLVMSetGlobalConstant(global_data, true); - LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2); + LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); string_map_set(&m->const_strings, key, ptr); return ptr; } @@ -2416,7 +2414,8 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) isize len = gb_snprintf(name, max_len, "csbs$%x", id); len -= 1; } - LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); + LLVMTypeRef type = LLVMTypeOf(data); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); LLVMSetInitializer(global_data, data); LLVMSetLinkage(global_data, LLVMPrivateLinkage); LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr); @@ -2425,7 +2424,7 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) LLVMValueRef ptr = nullptr; if (str.len != 0) { - ptr = LLVMConstInBoundsGEP(global_data, indices, 2); + ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); } else { ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 67f008a35..756a93db7 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1,3 +1,13 @@ + +LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count) +{ + unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); + GB_ASSERT_MSG(id != 0, "Unable to find %s", name); + LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, type_count); + LLVMTypeRef call_type = LLVMIntrinsicGetType(p->module->ctx, id, types, type_count); + return LLVMBuildCall2(p->builder, call_type, ip, args, arg_count, ""); +} + void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) { dst = lb_emit_conv(p, dst, t_rawptr); src = lb_emit_conv(p, src, t_rawptr); @@ -10,23 +20,23 @@ void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue l name = "llvm.memmove.inline"; } } - LLVMTypeRef types[3] = { lb_type(p->module, t_rawptr), lb_type(p->module, t_rawptr), lb_type(p->module, t_int) }; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]), LLVMPrintTypeToString(types[2])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[4] = {}; - args[0] = dst.value; - args[1] = src.value; - args[2] = len.value; - args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile); - LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + LLVMValueRef args[4] = { + dst.value, + src.value, + len.value, + LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile) + }; + + lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); } + + + void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) { dst = lb_emit_conv(p, dst, t_rawptr); src = lb_emit_conv(p, src, t_rawptr); @@ -45,16 +55,14 @@ void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbVal lb_type(p->module, t_rawptr), lb_type(p->module, t_int) }; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]), LLVMPrintTypeToString(types[2])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[4] = {}; - args[0] = dst.value; - args[1] = src.value; - args[2] = len.value; - args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile); - LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + + LLVMValueRef args[4] = { + dst.value, + src.value, + len.value, + LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile) }; + + lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); } @@ -122,7 +130,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) char *c_link_name = alloc_cstring(permanent_allocator(), p->name); LLVMTypeRef func_ptr_type = lb_type(m, p->type); - LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type); + LLVMTypeRef func_type = lb_llvm_get_pointer_type(func_ptr_type); p->value = LLVMAddFunction(m->mod, c_link_name, func_type); @@ -347,7 +355,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type char *c_link_name = alloc_cstring(permanent_allocator(), p->name); LLVMTypeRef func_ptr_type = lb_type(m, p->type); - LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type); + LLVMTypeRef func_type = lb_llvm_get_pointer_type(func_ptr_type); p->value = LLVMAddFunction(m->mod, c_link_name, func_type); @@ -750,7 +758,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) { fn = LLVMBuildPointerCast(p->builder, fn, ftp, ""); } - LLVMTypeRef fnp = LLVMGetElementType(LLVMTypeOf(fn)); + LLVMTypeRef fnp = lb_llvm_get_pointer_type(LLVMTypeOf(fn)); GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp)); { @@ -1264,13 +1272,8 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const } args[args_count++] = arg0.value; - LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - res.value = LLVMBuildCall(p->builder, ip, args, cast(unsigned)args_count, ""); + res.value = lb_call_intrinsic(p, name, args, cast(unsigned)args_count, types, gb_count_of(types)); return res; } case BuiltinProc_simd_reduce_min: @@ -1303,15 +1306,11 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const case BuiltinProc_simd_reduce_or: name = "llvm.vector.reduce.or"; break; case BuiltinProc_simd_reduce_xor: name = "llvm.vector.reduce.xor"; break; } - LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - LLVMValueRef args[1] = {}; - args[0] = arg0.value; + LLVMTypeRef types[1] = { lb_type(p->module, arg0.type) }; + LLVMValueRef args[1] = { arg0.value }; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); return res; } @@ -1360,15 +1359,10 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const case BuiltinProc_simd_nearest: name = "llvm.nearbyint"; break; } - LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[1] = {}; - args[0] = arg0.value; + LLVMTypeRef types[1] = { lb_type(p->module, arg0.type) }; + LLVMValueRef args[1] = { arg0.value }; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); return res; } @@ -1432,15 +1426,10 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const } LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - LLVMValueRef args[2] = {}; - args[0] = arg0.value; - args[1] = arg1.value; + LLVMValueRef args[2] = { arg0.value, arg1.value }; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); return res; } @@ -1903,11 +1892,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_trap: name = "llvm.trap"; break; } - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", name); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); - - LLVMBuildCall(p->builder, ip, nullptr, 0, ""); + lb_call_intrinsic(p, name, nullptr, 0, nullptr, 0); if (id == BuiltinProc_trap) { LLVMBuildUnreachable(p->builder); } @@ -1927,11 +1912,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, res.value = LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, ""); } else { char const *name = "llvm.readcyclecounter"; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", name); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); - - res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, ""); + res.value = lb_call_intrinsic(p, name, nullptr, 0, nullptr, 0); } return res; } @@ -1986,16 +1967,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } } LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - LLVMValueRef args[2] = {}; - args[0] = x.value; - args[1] = y.value; + LLVMValueRef args[2] = { x.value, y.value }; lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); if (is_type_tuple(main_type)) { Type *res_type = nullptr; @@ -2022,15 +1998,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, char const *name = "llvm.sqrt"; LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - LLVMValueRef args[1] = {}; - args[0] = x.value; + LLVMValueRef args[1] = { x.value }; lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); res.type = type; return res; } @@ -2045,17 +2017,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, char const *name = "llvm.fma"; LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - LLVMValueRef args[3] = {}; - args[0] = x.value; - args[1] = y.value; - args[2] = z.value; + LLVMValueRef args[3] = { x.value, y.value, z.value }; lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); res.type = type; return res; } @@ -2114,7 +2080,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, lbValue res = {}; res.type = tv.type; - res.value = LLVMBuildGEP(p->builder, ptr.value, indices, gb_count_of(indices), ""); + res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, type_deref(tv.type)), ptr.value, indices, gb_count_of(indices), ""); return res; } case BuiltinProc_ptr_sub: @@ -2123,7 +2089,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, lbValue ptr1 = lb_build_expr(p, ce->args[1]); LLVMTypeRef type_int = lb_type(p->module, t_int); - LLVMValueRef diff = LLVMBuildPtrDiff(p->builder, ptr0.value, ptr1.value, ""); + LLVMValueRef diff = LLVMBuildPtrDiff2(p->builder, lb_type(p->module, ptr0.type), ptr0.value, ptr1.value, ""); diff = LLVMBuildIntCast2(p->builder, diff, type_int, /*signed*/true, ""); lbValue res = {}; @@ -2174,7 +2140,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_atomic_load_explicit: { lbValue dst = lb_build_expr(p, ce->args[0]); - LLVMValueRef instr = LLVMBuildLoad(p->builder, dst.value, ""); + LLVMValueRef instr = LLVMBuildLoad2(p->builder, lb_type(p->module, type_deref(dst.type)), dst.value, ""); switch (id) { case BuiltinProc_non_temporal_load: { @@ -2348,18 +2314,14 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, GB_ASSERT(name != nullptr); LLVMTypeRef types[1] = {lb_type(p->module, platform_type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - lbValue res = {}; - LLVMValueRef args[3] = {}; - args[0] = x.value; - args[1] = y.value; - args[2] = scale.value; + LLVMValueRef args[3] = { + x.value, + y.value, + scale.value }; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); res.type = platform_type; return lb_emit_conv(p, res, tv.type); } @@ -2373,17 +2335,10 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, char const *name = "llvm.expect"; LLVMTypeRef types[1] = {lb_type(p->module, t)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - lbValue res = {}; + LLVMValueRef args[2] = { x.value, y.value }; - LLVMValueRef args[2] = {}; - args[0] = x.value; - args[1] = y.value; - - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); res.type = t; return lb_emit_conv(p, res, t); } @@ -2419,9 +2374,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, char const *name = "llvm.prefetch"; LLVMTypeRef types[1] = {lb_type(p->module, t_rawptr)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); LLVMTypeRef llvm_i32 = lb_type(p->module, t_i32); LLVMValueRef args[4] = {}; @@ -2431,7 +2383,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, args[3] = LLVMConstInt(llvm_i32, cache, false); lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); res.type = nullptr; return res; } @@ -2677,7 +2629,8 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, isize len = gb_snprintf(name, max_len, "csbs$%x", id); len -= 1; } - LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(array), name); + LLVMTypeRef type = LLVMTypeOf(array); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); LLVMSetInitializer(global_data, array); LLVMSetLinkage(global_data, LLVMInternalLinkage); @@ -2689,7 +2642,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, }; lbValue res = {}; res.type = tv.type; - res.value = LLVMBuildInBoundsGEP(p->builder, global_data, indices, gb_count_of(indices), ""); + res.value = LLVMBuildInBoundsGEP2(p->builder, type, global_data, indices, gb_count_of(indices), ""); return res; } @@ -2700,9 +2653,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, LLVMTypeRef types[1] = { lb_type(p->module, t_uintptr), }; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); LLVMValueRef args[2] = {}; args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value; @@ -2710,7 +2660,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, lbValue res = {}; res.type = tv.type; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); return res; } case BuiltinProc_wasm_memory_size: @@ -2719,16 +2669,13 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, LLVMTypeRef types[1] = { lb_type(p->module, t_uintptr), }; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); LLVMValueRef args[1] = {}; args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value; lbValue res = {}; res.type = tv.type; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); return res; } @@ -2738,9 +2685,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, LLVMTypeRef types[1] = { lb_type(p->module, t_u32), }; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); // types, gb_count_of(types)); Type *t_u32_ptr = alloc_type_pointer(t_u32); @@ -2751,7 +2695,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, lbValue res = {}; res.type = tv.type; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); return res; } @@ -2761,19 +2705,16 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, LLVMTypeRef types[1] = { lb_type(p->module, t_u32), }; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); // types, gb_count_of(types)); Type *t_u32_ptr = alloc_type_pointer(t_u32); - LLVMValueRef args[2] = {}; - args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32_ptr).value; - args[1] = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_u32).value; + LLVMValueRef args[2] = { + lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32_ptr).value, + lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_u32).value }; lbValue res = {}; res.type = tv.type; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); return res; } @@ -2782,7 +2723,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, { Type *param_types[2] = {t_u32, t_u32}; Type *type = alloc_type_proc_from_types(param_types, gb_count_of(param_types), tv.type, false, ProcCC_None); - LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, type)); + LLVMTypeRef func_type = lb_llvm_get_pointer_type(lb_type(p->module, type)); LLVMValueRef the_asm = llvm_get_inline_asm( func_type, str_lit("cpuid"), @@ -2802,7 +2743,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_x86_xgetbv: { Type *type = alloc_type_proc_from_types(&t_u32, 1, tv.type, false, ProcCC_None); - LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, type)); + LLVMTypeRef func_type = lb_llvm_get_pointer_type(lb_type(p->module, type)); LLVMValueRef the_asm = llvm_get_inline_asm( func_type, str_lit("xgetbv"), diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 2e7b2788a..844d6da31 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -104,7 +104,8 @@ lbValue lb_type_info(lbModule *m, Type *type) { }; lbValue value = {}; - value.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)); + lbValue data = lb_global_type_info_data_ptr(m); + value.value = LLVMConstGEP2(lb_type(m, type_deref(data.type)), data.value, indices, gb_count_of(indices)); value.type = t_type_info_ptr; return value; } @@ -123,10 +124,16 @@ lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { lbValue res = {}; res.type = t_type_info_ptr; - res.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, cast(unsigned)gb_count_of(indices)); + lbValue data = lb_global_type_info_data_ptr(m); + res.value = LLVMConstGEP2(lb_type(m, type_deref(data.type)), data.value, indices, cast(unsigned)gb_count_of(indices)); return res; } +// The use of this method needs to be eliminated. +LLVMTypeRef lb_llvm_get_pointer_type(LLVMTypeRef type) +{ + return LLVMGetElementType(type); +} lbValue lb_type_info_member_types_offset(lbProcedure *p, isize count) { GB_ASSERT(p->module == &p->module->gen->default_module); @@ -178,10 +185,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; LLVMValueRef values[2] = { - LLVMConstInBoundsGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)), + LLVMConstInBoundsGEP2(lb_type(m, lb_global_type_info_data_entity->type), lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)), LLVMConstInt(lb_type(m, t_int), type->Array.count, true), }; - LLVMValueRef slice = llvm_const_named_struct_internal(llvm_addr_type(global_type_table), values, gb_count_of(values)); + LLVMValueRef slice = llvm_const_named_struct_internal(lb_type(m, type_deref(global_type_table.type)), values, gb_count_of(values)); LLVMSetInitializer(global_type_table.value, slice); } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index bbacce7a2..08edf9693 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -79,9 +79,6 @@ LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValu lb_type(p->module, t_int) }; if (true || is_inlinable) { - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); LLVMValueRef args[4] = {}; args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], ""); @@ -89,16 +86,20 @@ LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValu args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, ""); args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), is_volatile, false); - return LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + return lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); } else { - LLVMValueRef ip = lb_lookup_runtime_procedure(p->module, str_lit("memset")).value; + lbValue pr = lb_lookup_runtime_procedure(p->module, str_lit("memset")); LLVMValueRef args[3] = {}; args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], ""); args[1] = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), 0, false); args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, ""); - return LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + // We always get the function pointer type rather than the function and there is apparently no way around that? + LLVMTypeRef type = lb_type(p->module, pr.type); + + type = lb_llvm_get_pointer_type(type); + return LLVMBuildCall2(p->builder, type, pr.value, args, gb_count_of(args), ""); } } @@ -483,15 +484,11 @@ lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) { char const *name = "llvm.bswap"; LLVMTypeRef types[1] = {lb_type(p->module, value.type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - LLVMValueRef args[1] = {}; - args[0] = value.value; + LLVMValueRef args[1] = { value.value }; lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); res.type = value.type; if (is_type_float(original_type)) { @@ -509,15 +506,10 @@ lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) { char const *name = "llvm.ctpop"; LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - - LLVMValueRef args[1] = {}; - args[0] = x.value; + LLVMValueRef args[1] = { x.value }; lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); res.type = type; return res; } @@ -538,16 +530,13 @@ lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) { char const *name = "llvm.cttz"; LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - LLVMValueRef args[2] = {}; - args[0] = x.value; - args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)); + LLVMValueRef args[2] = { + x.value, + LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)) }; lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); res.type = type; return res; } @@ -557,16 +546,13 @@ lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type) { char const *name = "llvm.ctlz"; LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - LLVMValueRef args[2] = {}; - args[0] = x.value; - args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)); + LLVMValueRef args[2] = { + x.value, + LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)) }; lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); res.type = type; return res; } @@ -578,15 +564,11 @@ lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) { char const *name = "llvm.bitreverse"; LLVMTypeRef types[1] = {lb_type(p->module, type)}; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0])); - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - LLVMValueRef args[1] = {}; - args[0] = x.value; + LLVMValueRef args[1] = { x.value }; lbValue res = {}; - res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); res.type = type; return res; } @@ -1020,12 +1002,12 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { lbModule *m = p->module; lbValue res = {}; LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)}; - res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); + res.value = LLVMConstGEP2(lb_type(m, type_deref(s.type)), s.value, indices, gb_count_of(indices)); res.type = alloc_type_pointer(result_type); return res; } else { lbValue res = {}; - LLVMTypeRef st = LLVMGetElementType(LLVMTypeOf(s.value)); + LLVMTypeRef st = lb_type(p->module, type_deref(s.type)); // gb_printf_err("%s\n", type_to_string(s.type)); // gb_printf_err("%s\n", LLVMPrintTypeToString(LLVMTypeOf(s.value))); // gb_printf_err("%d\n", index); @@ -1033,7 +1015,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { unsigned count = LLVMCountStructElementTypes(st); GB_ASSERT_MSG(count >= cast(unsigned)index, "%u %d %d", count, index, original_index); - res.value = LLVMBuildStructGEP(p->builder, s.value, cast(unsigned)index, ""); + res.value = LLVMBuildStructGEP2(p->builder, st, s.value, cast(unsigned)index, ""); res.type = alloc_type_pointer(result_type); return res; } @@ -1239,46 +1221,50 @@ lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) { Type *ptr = base_array_type(st); lbValue res = {}; - res.value = LLVMBuildGEP(p->builder, s.value, indices, 2, ""); + res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, st), s.value, indices, 2, ""); res.type = alloc_type_pointer(ptr); return res; } -lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) { - Type *t = s.type; - GB_ASSERT(is_type_pointer(t)); - Type *st = base_type(type_deref(t)); - GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); - - GB_ASSERT(0 <= index); - Type *ptr = base_array_type(st); - - +// This emits a GEP at 0, index +static inline lbValue lb_emit_gep(lbProcedure *p, Type *type, LLVMValueRef value, isize index) +{ LLVMValueRef indices[2] = { LLVMConstInt(lb_type(p->module, t_int), 0, false), LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)index, false), }; - + LLVMTypeRef llvm_type = lb_type(p->module, type); lbValue res = {}; - if (lb_is_const(s)) { - res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); + Type *ptr = base_array_type(type); + res.type = alloc_type_pointer(ptr); + if (LLVMIsConstant(value)) { + res.value = LLVMConstGEP2(llvm_type, value, indices, gb_count_of(indices)); } else { - res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), ""); + res.value = LLVMBuildGEP2(p->builder, llvm_type, value, indices, gb_count_of(indices), ""); } - res.type = alloc_type_pointer(ptr); return res; } +lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) { + Type *t = s.type; + GB_ASSERT(is_type_pointer(t)); + Type *st = base_type(type_deref(t)); + GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); + GB_ASSERT(0 <= index); + return lb_emit_gep(p, st, s.value, index); +} + lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) { index = lb_emit_conv(p, index, t_int); LLVMValueRef indices[1] = {index.value}; lbValue res = {}; res.type = ptr.type; + LLVMTypeRef type = lb_type(p->module, type_deref(ptr.type)); if (lb_is_const(ptr) && lb_is_const(index)) { - res.value = LLVMConstGEP(ptr.value, indices, 1); + res.value = LLVMConstGEP2(type, ptr.value, indices, 1); } else { - res.value = LLVMBuildGEP(p->builder, ptr.value, indices, 1, ""); + res.value = LLVMBuildGEP2(p->builder, type, ptr.value, indices, 1, ""); } return res; } @@ -1287,63 +1273,18 @@ lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column) { Type *t = s.type; GB_ASSERT(is_type_pointer(t)); Type *mt = base_type(type_deref(t)); - - Type *ptr = base_array_type(mt); - if (column == 0) { GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt)); - - LLVMValueRef indices[2] = { - LLVMConstInt(lb_type(p->module, t_int), 0, false), - LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)row, false), - }; - - lbValue res = {}; - if (lb_is_const(s)) { - res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); - } else { - res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), ""); - } - - Type *ptr = base_array_type(mt); - res.type = alloc_type_pointer(ptr); - return res; + return lb_emit_gep(p, mt, s.value, row); } else if (row == 0 && is_type_array_like(mt)) { - LLVMValueRef indices[2] = { - LLVMConstInt(lb_type(p->module, t_int), 0, false), - LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)column, false), - }; - - lbValue res = {}; - if (lb_is_const(s)) { - res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); - } else { - res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), ""); - } - - Type *ptr = base_array_type(mt); - res.type = alloc_type_pointer(ptr); - return res; + return lb_emit_gep(p, mt, s.value, column); } GB_ASSERT_MSG(is_type_matrix(mt), "%s", type_to_string(mt)); isize offset = matrix_indices_to_offset(mt, row, column); - - LLVMValueRef indices[2] = { - LLVMConstInt(lb_type(p->module, t_int), 0, false), - LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)offset, false), - }; - - lbValue res = {}; - if (lb_is_const(s)) { - res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); - } else { - res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), ""); - } - res.type = alloc_type_pointer(ptr); - return res; + return lb_emit_gep(p, mt, s.value, offset); } lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column) { @@ -1366,11 +1307,12 @@ lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column index, }; + LLVMTypeRef type = lb_type(p->module, mt); lbValue res = {}; if (lb_is_const(s)) { - res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); + res.value = LLVMConstGEP2(type, s.value, indices, gb_count_of(indices)); } else { - res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), ""); + res.value = LLVMBuildGEP2(p->builder, type, s.value, indices, gb_count_of(indices), ""); } res.type = alloc_type_pointer(ptr); return res; @@ -1574,18 +1516,12 @@ lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t if (is_possible) { char const *name = "llvm.fma"; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", name); - - LLVMTypeRef types[1] = {}; - types[0] = lb_type(m, t); - - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(m->mod, id, types, gb_count_of(types)); - LLVMValueRef values[3] = {}; - values[0] = a.value; - values[1] = b.value; - values[2] = c.value; - LLVMValueRef call = LLVMBuildCall(p->builder, ip, values, gb_count_of(values), ""); + LLVMTypeRef types[1] = { lb_type(m, t) }; + LLVMValueRef values[3] = { + a.value, + b.value, + c.value }; + LLVMValueRef call = lb_call_intrinsic(p, name, values, gb_count_of(values), types, gb_count_of(types)); return {call, t}; } else { lbValue x = lb_emit_arith(p, Token_Mul, a, b, t); @@ -1714,15 +1650,9 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) { unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); if (id != 0 && false) { - LLVMTypeRef types[1] = {}; - types[0] = type; - - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); - LLVMValueRef values[2] = {}; - values[0] = LLVMConstNull(elem); - values[1] = value; - LLVMValueRef call = LLVMBuildCall(p->builder, ip, values+value_offset, value_count, ""); - return call; + LLVMTypeRef types[1] = { type }; + LLVMValueRef values[2] = { LLVMConstNull(elem), value }; + return lb_call_intrinsic(p, name, values + value_offset, value_count, types, gb_count_of(types)); } // Manual reduce @@ -1791,8 +1721,7 @@ LLVMValueRef llvm_vector_dot(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) { } LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, LLVMValueRef c) { - lbModule *m = p->module; - + LLVMTypeRef t = LLVMTypeOf(a); GB_ASSERT(t == LLVMTypeOf(b)); GB_ASSERT(t == LLVMTypeOf(c)); @@ -1814,18 +1743,9 @@ LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, if (is_possible) { char const *name = "llvm.fmuladd"; - unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); - GB_ASSERT_MSG(id != 0, "Unable to find %s", name); - - LLVMTypeRef types[1] = {}; - types[0] = t; - - LLVMValueRef ip = LLVMGetIntrinsicDeclaration(m->mod, id, types, gb_count_of(types)); - LLVMValueRef values[3] = {}; - values[0] = a; - values[1] = b; - values[2] = c; - LLVMValueRef call = LLVMBuildCall(p->builder, ip, values, gb_count_of(values), ""); + LLVMTypeRef types[1] = { t }; + LLVMValueRef values[3] = { a, b, c}; + LLVMValueRef call = lb_call_intrinsic(p, name, values, gb_count_of(values), types, gb_count_of(types)); return call; } else { LLVMValueRef x = llvm_vector_mul(p, a, b); @@ -1840,7 +1760,7 @@ LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, Strin cast(char *)clobbers.text, cast(size_t)clobbers.len, has_side_effects, is_align_stack, dialect - #if LLVM_VERSION_MAJOR >= 13 + #if LLVM_VERSION_MAJOR >= 13 , /*CanThrow*/false #endif ); -- cgit v1.2.3 From c1c8ceafc243389d8eb94feca99de1239da32408 Mon Sep 17 00:00:00 2001 From: Ian Lilley Date: Sun, 7 Aug 2022 17:52:29 -0400 Subject: find windows sdk bin path for rc.exe --- src/build_settings.cpp | 8 +- src/main.cpp | 6 +- src/microsoft_craziness.h | 355 ++++++++++++++++++++++++---------------------- src/string.cpp | 10 ++ 4 files changed, 201 insertions(+), 178 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 65da09df0..d49f1cecf 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -204,7 +204,7 @@ enum BuildPath : u8 { BuildPath_Main_Package, // Input Path to the package directory (or file) we're building. BuildPath_RC, // Input Path for .rc file, can be set with `-resource:`. BuildPath_RES, // Output Path for .res file, generated from previous. - BuildPath_Win_SDK_Root, // windows_sdk_root + BuildPath_Win_SDK_Bin_Path, // windows_sdk_bin_path BuildPath_Win_SDK_UM_Lib, // windows_sdk_um_library_path BuildPath_Win_SDK_UCRT_Lib, // windows_sdk_ucrt_library_path BuildPath_VS_EXE, // vs_exe_path @@ -1336,7 +1336,7 @@ bool init_build_paths(String init_filename) { if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) { // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. - Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); + Find_Result find_result = find_visual_studio_and_windows_sdk(); defer (mc_free_all()); if (find_result.windows_sdk_version == 0) { @@ -1357,8 +1357,8 @@ bool init_build_paths(String init_filename) { if (find_result.windows_sdk_um_library_path.len > 0) { GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); - if (find_result.windows_sdk_root.len > 0) { - bc->build_paths[BuildPath_Win_SDK_Root] = path_from_string(ha, find_result.windows_sdk_root); + if (find_result.windows_sdk_bin_path.len > 0) { + bc->build_paths[BuildPath_Win_SDK_Bin_Path] = path_from_string(ha, find_result.windows_sdk_bin_path); } if (find_result.windows_sdk_um_library_path.len > 0) { diff --git a/src/main.cpp b/src/main.cpp index beefec702..7fa04cc37 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -283,6 +283,9 @@ i32 linker_stage(lbGenerator *gen) { String vs_exe_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_VS_EXE]); defer (gb_free(heap_allocator(), vs_exe_path.text)); + String windows_sdk_bin_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Win_SDK_Bin_Path]); + defer (gb_free(heap_allocator(), windows_sdk_bin_path.text)); + char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; if (!build_context.use_lld) { // msvc if (build_context.has_resource) { @@ -292,7 +295,8 @@ i32 linker_stage(lbGenerator *gen) { defer (gb_free(heap_allocator(), res_path.text)); result = system_exec_command_line_app("msvc-link", - "\"rc.exe\" /nologo /fo \"%.*s\" \"%.*s\"", + "\"%.*src.exe\" /nologo /fo \"%.*s\" \"%.*s\"", + LIT(windows_sdk_bin_path), LIT(res_path), LIT(rc_path) ); diff --git a/src/microsoft_craziness.h b/src/microsoft_craziness.h index 812513875..7d23f2557 100644 --- a/src/microsoft_craziness.h +++ b/src/microsoft_craziness.h @@ -50,18 +50,7 @@ gb_global gbAllocator mc_allocator = heap_allocator(); struct Find_Result { int windows_sdk_version; // Zero if no Windows SDK found. - wchar_t const *windows_sdk_root; - wchar_t const *windows_sdk_um_library_path; - wchar_t const *windows_sdk_ucrt_library_path; - - wchar_t const *vs_exe_path; - wchar_t const *vs_library_path; -}; - -struct Find_Result_Utf8 { - int windows_sdk_version; // Zero if no Windows SDK found. - - String windows_sdk_root; + String windows_sdk_bin_path; String windows_sdk_um_library_path; String windows_sdk_ucrt_library_path; @@ -69,8 +58,6 @@ struct Find_Result_Utf8 { String vs_library_path; }; -Find_Result_Utf8 find_visual_studio_and_windows_sdk_utf8(); - String mc_wstring_to_string(wchar_t const *str) { return string16_to_string(mc_allocator, make_string16_c(str)); } @@ -87,6 +74,10 @@ String mc_concat(String a, String b, String c) { return concatenate3_strings(mc_allocator, a, b, c); } +String mc_concat(String a, String b, String c, String d) { + return concatenate4_strings(mc_allocator, a, b, c, d); +} + String mc_get_env(String key) { char const * value = gb_get_env((char const *)key.text, mc_allocator); return make_string_c(value); @@ -219,19 +210,19 @@ struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") DECLSPEC_NOVTABLE I // The beginning of the actual code that does things. -struct Version_Data_Utf8 { - i32 best_version[4]; // For Windows 8 versions, only two of these numbers are used. +struct Version_Data { + i32 best_version[4]; String best_name; }; -typedef void (*MC_Visit_Proc)(String short_name, String full_name, Version_Data_Utf8 *data); -bool mc_visit_files(String dir_name, Version_Data_Utf8 *data, MC_Visit_Proc proc) { +typedef void (*MC_Visit_Proc)(String short_name, String full_name, Version_Data *data); +bool mc_visit_files(String dir_name, Version_Data *data, MC_Visit_Proc proc) { // Visit everything in one folder (non-recursively). If it's a directory // that doesn't start with ".", call the visit proc on it. The visit proc // will see if the filename conforms to the expected versioning pattern. - String wildcard_name = mc_concat(dir_name, str_lit("\\*")); + String wildcard_name = mc_concat(dir_name, str_lit("*")); defer (mc_free(wildcard_name)); MC_Find_Data find_data; @@ -242,7 +233,7 @@ bool mc_visit_files(String dir_name, Version_Data_Utf8 *data, MC_Visit_Proc proc bool success = true; while (success) { if ((find_data.file_attributes & FILE_ATTRIBUTE_DIRECTORY) && (find_data.filename[0] != '.')) { - String full_name = mc_concat(dir_name, str_lit("\\"), find_data.filename); + String full_name = mc_concat(dir_name, find_data.filename); defer (mc_free(full_name)); proc(find_data.filename, full_name, data); @@ -284,7 +275,7 @@ String find_windows_kit_root(HKEY key, String const version) { return value; } -void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) { +void win10_best(String short_name, String full_name, Version_Data *data) { // Find the Windows 10 subdirectory with the highest version number. int i0, i1, i2, i3; @@ -304,11 +295,11 @@ void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) { // we have to copy_string and free here because visit_files free's the full_name string // after we execute this function, so Win*_Data would contain an invalid pointer. - if (data->best_name.len > 0) mc_free(data->best_name); + if (data->best_name.len) mc_free(data->best_name); data->best_name = copy_string(mc_allocator, full_name); - if (data->best_name.len > 0) { + if (data->best_name.len) { data->best_version[0] = i0; data->best_version[1] = i1; data->best_version[2] = i2; @@ -316,34 +307,8 @@ void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) { } } -void win8_best(String short_name, String full_name, Version_Data_Utf8 *data) { - // Find the Windows 8 subdirectory with the highest version number. - - int i0, i1; - auto success = sscanf_s((const char *const)short_name.text, "winv%d.%d", &i0, &i1); - if (success < 2) return; - - if (i0 < data->best_version[0]) return; - else if (i0 == data->best_version[0]) { - if (i1 < data->best_version[1]) return; - } - - // we have to copy_string and free here because visit_files free's the full_name string - // after we execute this function, so Win*_Data would contain an invalid pointer. - if (data->best_name.len > 0) mc_free(data->best_name); - data->best_name = copy_string(mc_allocator, full_name); - - if (data->best_name.len > 0) { - data->best_version[0] = i0; - data->best_version[1] = i1; - } -} - -void find_windows_kit_root(Find_Result_Utf8 *result) { - // Information about the Windows 10 and Windows 8 development kits - // is stored in the same place in the registry. We open a key - // to that place, first checking preferntially for a Windows 10 kit, - // then, if that's not found, a Windows 8 kit. +void find_windows_kit_paths(Find_Result *result) { + bool sdk_found = false; HKEY main_key; @@ -355,44 +320,42 @@ void find_windows_kit_root(Find_Result_Utf8 *result) { // Look for a Windows 10 entry. String windows10_root = find_windows_kit_root(main_key, str_lit("KitsRoot10")); - if (windows10_root.len > 0) { + if (windows10_root.len) { defer (mc_free(windows10_root)); - String windows10_lib = mc_concat(windows10_root, str_lit("Lib")); + String windows10_lib = mc_concat(windows10_root, str_lit("Lib\\")); + Version_Data data_lib = {0}; + mc_visit_files(windows10_lib, &data_lib, win10_best); defer (mc_free(windows10_lib)); + defer (mc_free(data_lib.best_name)); + + String windows10_bin = mc_concat(windows10_root, str_lit("bin\\")); + Version_Data data_bin = {0}; + mc_visit_files(windows10_bin, &data_bin, win10_best); + defer (mc_free(windows10_bin)); + defer (mc_free(data_bin.best_name)); - Version_Data_Utf8 data = {0}; - mc_visit_files(windows10_lib, &data, win10_best); - if (data.best_name.len > 0) { - result->windows_sdk_version = 10; - result->windows_sdk_root = mc_concat(data.best_name, str_lit("\\")); - return; + if (data_lib.best_name.len && data_bin.best_name.len) { + if (build_context.metrics.arch == TargetArch_amd64) { + result->windows_sdk_um_library_path = mc_concat(data_lib.best_name, str_lit("\\um\\x64\\")); + result->windows_sdk_ucrt_library_path = mc_concat(data_lib.best_name, str_lit("\\ucrt\\x64\\")); + result->windows_sdk_bin_path = mc_concat(data_bin.best_name, str_lit("\\x64\\")); + sdk_found = true; + } else if (build_context.metrics.arch == TargetArch_i386) { + result->windows_sdk_um_library_path = mc_concat(data_lib.best_name, str_lit("\\um\\x86\\")); + result->windows_sdk_ucrt_library_path = mc_concat(data_lib.best_name, str_lit("\\ucrt\\x86\\")); + result->windows_sdk_bin_path = mc_concat(data_bin.best_name, str_lit("\\x86\\")); + sdk_found = true; + } } - mc_free(data.best_name); } - // Look for a Windows 8 entry. - String windows8_root = find_windows_kit_root(main_key, str_lit("KitsRoot81")); - - if (windows8_root.len > 0) { - defer (mc_free(windows8_root)); - - String windows8_lib = mc_concat(windows8_root, str_lit("Lib")); - defer (mc_free(windows8_lib)); - - Version_Data_Utf8 data = {0}; - mc_visit_files(windows8_lib, &data, win8_best); - if (data.best_name.len > 0) { - result->windows_sdk_version = 8; - result->windows_sdk_root = mc_concat(data.best_name, str_lit("\\")); - return; - } - mc_free(data.best_name); + if (sdk_found) { + result->windows_sdk_version = 10; } - // If we get here, we failed to find anything. } -bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result_Utf8 *result) { +bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *result) { // The name of this procedure is kind of cryptic. Its purpose is // to fight through Microsoft craziness. The things that the fine // Visual Studio team want you to do, JUST TO FIND A SINGLE FOLDER @@ -555,54 +518,97 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result_Utf8 } // NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both -// official and portable installations (like mmozeiko's portable msvc script). This will only use -// the first paths it finds, and won't overwrite any values that `result` already has. -bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) { +// official and portable installations (like mmozeiko's portable msvc script). +void find_windows_kit_paths_from_env_vars(Find_Result *result) { if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) { - return false; + return; } - // We can find windows sdk using the following combination of env vars: - // (UniversalCRTSdkDir or WindowsSdkDir) and (WindowsSDKLibVersion or WindowsSDKVersion) - bool sdk_found = false; + // We can find windows sdk lib dir using the following combination of env vars: + // (WindowsSdkDir or UniversalCRTSdkDir) and (WindowsSDKVersion or WindowsSDKLibVersion) + bool sdk_lib_found = false; + + // We can find windows sdk bin dir using the following combination of env vars: + // (WindowsSdkVerBinPath) or ((WindowsSdkBinPath or WindowsSdkDir or UniversalCRTSdkDir) and (WindowsSDKVersion || WindowsSDKLibVersion)) + bool sdk_bin_found = false; // These appear to be suitable env vars used by Visual Studio String win_sdk_ver_env = mc_get_env(str_lit("WindowsSDKVersion")); - String win_sdk_lib_env = mc_get_env(str_lit("WindowsSDKLibVersion")); + String win_sdk_lib_ver_env = mc_get_env(str_lit("WindowsSDKLibVersion")); String win_sdk_dir_env = mc_get_env(str_lit("WindowsSdkDir")); String crt_sdk_dir_env = mc_get_env(str_lit("UniversalCRTSdkDir")); + String win_sdk_bin_path_env = mc_get_env(str_lit("WindowsSdkBinPath")); + String win_sdk_ver_bin_path_env = mc_get_env(str_lit("WindowsSdkVerBinPath")); defer ({ mc_free(win_sdk_ver_env); - mc_free(win_sdk_lib_env); + mc_free(win_sdk_lib_ver_env); mc_free(win_sdk_dir_env); mc_free(crt_sdk_dir_env); + mc_free(win_sdk_bin_path_env); + mc_free(win_sdk_ver_bin_path_env); }); + if (win_sdk_ver_bin_path_env.len || ((win_sdk_bin_path_env.len || win_sdk_dir_env.len || crt_sdk_dir_env.len) && (win_sdk_ver_env.len || win_sdk_lib_ver_env.len))) { + String bin; + defer (mc_free(bin)); + + if (win_sdk_ver_bin_path_env.len) { + String dir = win_sdk_ver_bin_path_env; + + // Add trailing '\' in case it was missing + bin = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit("")); + } else { + String dir = win_sdk_bin_path_env.len ? win_sdk_bin_path_env : win_sdk_dir_env.len ? win_sdk_dir_env : crt_sdk_dir_env; + String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_ver_env; + + // Add trailing '\' in case it was missing + dir = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit("")); + ver = mc_concat(ver, ver[ver.len - 1] != '\\' ? str_lit("\\") : str_lit("")); + defer (mc_free(dir)); + defer (mc_free(ver)); + + // Append "bin" for win_sdk_dir_env and crt_sdk_dir_env + String dir_bin = mc_concat(dir, win_sdk_bin_path_env.len ? str_lit("") : str_lit("bin\\")); + defer (mc_free(dir_bin)); + + bin = mc_concat(dir_bin, ver); + } + + if (build_context.metrics.arch == TargetArch_amd64) { + result->windows_sdk_bin_path = mc_concat(bin, str_lit("x64\\")); + sdk_bin_found = true; + } else if (build_context.metrics.arch == TargetArch_i386) { + result->windows_sdk_bin_path = mc_concat(bin, str_lit("x86\\")); + sdk_bin_found = true; + } + } + // NOTE(WalterPlinge): If any combination is found, let's just assume they are correct - if ((win_sdk_ver_env.len || win_sdk_lib_env.len) && (win_sdk_dir_env.len || crt_sdk_dir_env.len)) { - //? Maybe we need to handle missing '\' at end of strings, so far it doesn't seem an issue + if ((win_sdk_ver_env.len || win_sdk_lib_ver_env.len) && (win_sdk_dir_env.len || crt_sdk_dir_env.len)) { String dir = win_sdk_dir_env.len ? win_sdk_dir_env : crt_sdk_dir_env; - String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_env; - - // These have trailing '\' as we are just composing the path - String um_dir = build_context.metrics.arch == TargetArch_amd64 - ? str_lit("um\\x64\\") - : str_lit("um\\x86\\"); - String ucrt_dir = build_context.metrics.arch == TargetArch_amd64 - ? str_lit("ucrt\\x64\\") - : str_lit("ucrt\\x86\\"); + String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_ver_env; - result->windows_sdk_root = mc_concat(dir, str_lit("Lib\\"), ver); - result->windows_sdk_um_library_path = mc_concat(result->windows_sdk_root, um_dir); - result->windows_sdk_ucrt_library_path = mc_concat(result->windows_sdk_root, ucrt_dir); + // Add trailing '\' in case it was missing + dir = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit("")); + ver = mc_concat(ver, ver[ver.len - 1] != '\\' ? str_lit("\\") : str_lit("")); + defer (mc_free(dir)); + defer (mc_free(ver)); - sdk_found = true; + if (build_context.metrics.arch == TargetArch_amd64) { + result->windows_sdk_um_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("um\\x64\\")); + result->windows_sdk_ucrt_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("ucrt\\x64\\")); + sdk_lib_found = true; + } else if (build_context.metrics.arch == TargetArch_i386) { + result->windows_sdk_um_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("um\\x86\\")); + result->windows_sdk_ucrt_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("ucrt\\x86\\")); + sdk_lib_found = true; + } } // If we haven't found it yet, we can loop through LIB for specific folders //? This may not be robust enough using `um\x64` and `ucrt\x64` - if (!sdk_found) { + if (!sdk_lib_found) { String lib = mc_get_env(str_lit("LIB")); defer (mc_free(lib)); @@ -624,38 +630,30 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) { continue; } hi = c; - String dir = substring(lib, lo, hi); defer (lo = hi + 1); + // Skip when there are two ;; in a row + if (lo == hi) { + continue; + } + + String dir = substring(lib, lo, hi); + // Remove the last slash so we can match with the strings above String end = dir[dir.len - 1] == '\\' ? substring(dir, 0, dir.len - 1) : substring(dir, 0, dir.len); - // Find one and we can make the other if (string_ends_with(end, um_dir)) { - result->windows_sdk_um_library_path = mc_concat(end, str_lit("\\")); - break; + result->windows_sdk_um_library_path = mc_concat(end, str_lit("\\")); } else if (string_ends_with(end, ucrt_dir)) { result->windows_sdk_ucrt_library_path = mc_concat(end, str_lit("\\")); - break; } - } - - // Get the root from the one we found, and make the other - // NOTE(WalterPlinge): we need to copy the string so that we don't risk a double free - if (result->windows_sdk_um_library_path.len > 0) { - String root = substring(result->windows_sdk_um_library_path, 0, result->windows_sdk_um_library_path.len - 1 - um_dir.len); - result->windows_sdk_root = copy_string(mc_allocator, root); - result->windows_sdk_ucrt_library_path = mc_concat(result->windows_sdk_root, ucrt_dir, str_lit("\\")); - } else if (result->windows_sdk_ucrt_library_path.len > 0) { - String root = substring(result->windows_sdk_ucrt_library_path, 0, result->windows_sdk_ucrt_library_path.len - 1 - ucrt_dir.len); - result->windows_sdk_root = copy_string(mc_allocator, root); - result->windows_sdk_um_library_path = mc_concat(result->windows_sdk_root, um_dir, str_lit("\\")); - } - if (result->windows_sdk_root.len > 0) { - sdk_found = true; + if (result->windows_sdk_um_library_path.len && result->windows_sdk_ucrt_library_path.len) { + sdk_lib_found = true; + break; + } } } } @@ -663,33 +661,36 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) { // NOTE(WalterPlinge): So far this function assumes it will only be called if MSVC was // installed using mmozeiko's portable msvc script, which uses the windows 10 sdk. // This may need to be changed later if it ends up causing problems. - if (sdk_found && result->windows_sdk_version == 0) { + if (sdk_bin_found && sdk_lib_found) { result->windows_sdk_version = 10; } +} - bool vs_found = false; - - if (result->vs_exe_path.len > 0 && result->vs_library_path.len > 0) { - vs_found = true; +// NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both +// official and portable installations (like mmozeiko's portable msvc script). This will only use +// the first paths it finds, and won't overwrite any values that `result` already has. +void find_visual_studio_paths_from_env_vars(Find_Result *result) { + if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) { + return; } - // We can find visual studio using VCToolsInstallDir - if (!vs_found) { - String vctid = mc_get_env(str_lit("VCToolsInstallDir")); - defer (mc_free(vctid)); - - if (vctid.len) { - String exe = build_context.metrics.arch == TargetArch_amd64 - ? str_lit("bin\\Hostx64\\x64\\") - : str_lit("bin\\Hostx86\\x86\\"); - String lib = build_context.metrics.arch == TargetArch_amd64 - ? str_lit("lib\\x64\\") - : str_lit("lib\\x86\\"); + bool vs_found = false; - result->vs_exe_path = mc_concat(vctid, exe); - result->vs_library_path = mc_concat(vctid, lib); - vs_found = true; - } + // We can find visual studio using VCToolsInstallDir + String vctid = mc_get_env(str_lit("VCToolsInstallDir")); + defer (mc_free(vctid)); + + if (vctid.len) { + String exe = build_context.metrics.arch == TargetArch_amd64 + ? str_lit("bin\\Hostx64\\x64\\") + : str_lit("bin\\Hostx86\\x86\\"); + String lib = build_context.metrics.arch == TargetArch_amd64 + ? str_lit("lib\\x64\\") + : str_lit("lib\\x86\\"); + + result->vs_exe_path = mc_concat(vctid, exe); + result->vs_library_path = mc_concat(vctid, lib); + vs_found = true; } // If we haven't found it yet, we can loop through Path for specific folders @@ -701,21 +702,32 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) { String exe = build_context.metrics.arch == TargetArch_amd64 ? str_lit("bin\\Hostx64\\x64") : str_lit("bin\\Hostx86\\x86"); + // The environment variable may have an uppercase X even though the folder is lowercase + String exe2 = build_context.metrics.arch == TargetArch_amd64 + ? str_lit("bin\\HostX64\\x64") + : str_lit("bin\\HostX86\\x86"); String lib = build_context.metrics.arch == TargetArch_amd64 ? str_lit("lib\\x64") : str_lit("lib\\x86"); isize lo = {0}; isize hi = {0}; - for (isize c = 0; c < path.len; c += 1) { - if (path[c] != ';') { + for (isize c = 0; c <= path.len; c += 1) { + if (c != path.len && path[c] != ';') { continue; } hi = c; - String dir = substring(path, lo, hi); defer (lo = hi + 1); + // Skip when there are two ;; in a row + if (lo == hi) { + continue; + } + + String dir = substring(path, lo, hi); + + // Remove the last slash so we can match with the strings above String end = dir[dir.len - 1] == '\\' ? substring(dir, 0, dir.len - 1) : substring(dir, 0, dir.len); @@ -726,7 +738,10 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) { defer (mc_free(cl)); defer (mc_free(link)); - if (!string_ends_with(end, exe) || !gb_file_exists((char *)cl.text) || !gb_file_exists((char *)link.text)) { + if (!string_ends_with(end, exe) && !string_ends_with(end, exe2)) { + continue; + } + if (!gb_file_exists((char *)cl.text) || !gb_file_exists((char *)link.text)) { continue; } @@ -735,42 +750,36 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) { result->vs_library_path = mc_concat(root, lib, str_lit("\\")); vs_found = true; + break; } } } - - return sdk_found && vs_found; } -Find_Result_Utf8 find_visual_studio_and_windows_sdk_utf8() { - Find_Result_Utf8 r = {}; - find_windows_kit_root(&r); +Find_Result find_visual_studio_and_windows_sdk() { + Find_Result r = {}; + find_windows_kit_paths(&r); + find_visual_studio_by_fighting_through_microsoft_craziness(&r); - if (r.windows_sdk_root.len > 0) { - if (build_context.metrics.arch == TargetArch_amd64) { - r.windows_sdk_um_library_path = mc_concat(r.windows_sdk_root, str_lit("um\\x64\\")); - r.windows_sdk_ucrt_library_path = mc_concat(r.windows_sdk_root, str_lit("ucrt\\x64\\")); - } else if (build_context.metrics.arch == TargetArch_i386) { - r.windows_sdk_um_library_path = mc_concat(r.windows_sdk_root, str_lit("um\\x86\\")); - r.windows_sdk_ucrt_library_path = mc_concat(r.windows_sdk_root, str_lit("ucrt\\x86\\")); - } - } + bool sdk_found = + r.windows_sdk_bin_path.len && + r.windows_sdk_um_library_path.len && + r.windows_sdk_ucrt_library_path.len ; - find_visual_studio_by_fighting_through_microsoft_craziness(&r); + bool vs_found = + r.vs_exe_path.len && + r.vs_library_path.len ; - bool all_found = - r.windows_sdk_root.len > 0 && - r.windows_sdk_um_library_path.len > 0 && - r.windows_sdk_ucrt_library_path.len > 0 && - r.vs_exe_path.len > 0 && - r.vs_library_path.len > 0; + if (!sdk_found) { + find_windows_kit_paths_from_env_vars(&r); + } - if (!all_found) { - find_msvc_install_from_env_vars(&r); + if (!vs_found) { + find_visual_studio_paths_from_env_vars(&r); } #if 0 - printf("windows_sdk_root: %.*s\n", LIT(r.windows_sdk_root)); + printf("windows_sdk_bin_path: %.*s\n", LIT(r.windows_sdk_bin_path)); printf("windows_sdk_um_library_path: %.*s\n", LIT(r.windows_sdk_um_library_path)); printf("windows_sdk_ucrt_library_path: %.*s\n", LIT(r.windows_sdk_ucrt_library_path)); printf("vs_exe_path: %.*s\n", LIT(r.vs_exe_path)); diff --git a/src/string.cpp b/src/string.cpp index 44eccd2d2..bc55e370c 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -324,6 +324,16 @@ String concatenate3_strings(gbAllocator a, String const &x, String const &y, Str data[len] = 0; return make_string(data, len); } +String concatenate4_strings(gbAllocator a, String const &x, String const &y, String const &z, String const &w) { + isize len = x.len+y.len+z.len+w.len; + u8 *data = gb_alloc_array(a, u8, len+1); + gb_memmove(data, x.text, x.len); + gb_memmove(data+x.len, y.text, y.len); + gb_memmove(data+x.len+y.len, z.text, z.len); + gb_memmove(data+x.len+y.len+z.len, w.text, w.len); + data[len] = 0; + return make_string(data, len); +} String string_join_and_quote(gbAllocator a, Array strings) { if (!strings.count) { -- cgit v1.2.3 From 5e3cf45df3e781b0e5e01a55490a32bed0d9c7e3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 8 Aug 2022 15:07:00 +0100 Subject: Add `#soa` pointer type to aid with refactoring to `#soa` data types a: #soa[16]Foo p := &a[6] #assert(type_of(p) == #soa^#soa[16]Foo) p^.x = 123 p.x = 123 --- core/encoding/json/marshal.odin | 3 ++ core/fmt/fmt.odin | 13 +++++++++ core/mem/raw.odin | 1 + core/odin/ast/ast.odin | 1 + core/odin/ast/clone.odin | 1 + core/odin/doc-format/doc_format.odin | 2 ++ core/odin/parser/parser.odin | 16 ++++++++++- core/reflect/reflect.odin | 5 ++++ core/reflect/types.odin | 13 +++++++++ core/runtime/core.odin | 10 +++++++ core/runtime/print.odin | 3 ++ src/check_decl.cpp | 2 +- src/check_expr.cpp | 22 ++++++++++---- src/check_type.cpp | 28 +++++++++++++++--- src/checker.cpp | 11 +++++++ src/docs_format.cpp | 1 + src/docs_writer.cpp | 4 +++ src/llvm_backend_expr.cpp | 33 ++++++++++++++++++--- src/llvm_backend_general.cpp | 15 ++++++++++ src/llvm_backend_type.cpp | 15 ++++++++++ src/llvm_backend_utility.cpp | 35 +++++++++++++++++++++- src/parser.cpp | 6 ++-- src/parser.hpp | 3 +- src/types.cpp | 56 ++++++++++++++++++++++++++++++++---- 24 files changed, 275 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index 54fab44c6..c0e70c85c 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -147,6 +147,9 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) { case runtime.Type_Info_Multi_Pointer: return .Unsupported_Type + case runtime.Type_Info_Soa_Pointer: + return .Unsupported_Type + case runtime.Type_Info_Procedure: return .Unsupported_Type diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 4db140afa..0973e7366 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1031,6 +1031,15 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) { } } +fmt_soa_pointer :: proc(fi: ^Info, p: runtime.Raw_Soa_Pointer, verb: rune) { + io.write_string(fi.writer, "#soa{0x", &fi.n) + _fmt_int(fi, u64(uintptr(p.data)), 16, false, 8*size_of(rawptr), __DIGITS_UPPER) + io.write_string(fi.writer, ", ", &fi.n) + _fmt_int(fi, u64(p.index), 10, false, 8*size_of(rawptr), __DIGITS_UPPER) + io.write_string(fi.writer, "}", &fi.n) +} + + enum_value_to_string :: proc(val: any) -> (string, bool) { v := val v.id = runtime.typeid_base(v.id) @@ -1867,6 +1876,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { fmt_pointer(fi, ptr, verb) } + case runtime.Type_Info_Soa_Pointer: + ptr := (^runtime.Raw_Soa_Pointer)(v.data)^ + fmt_soa_pointer(fi, ptr, verb) + case runtime.Type_Info_Multi_Pointer: ptr := (^rawptr)(v.data)^ if ptr == nil { diff --git a/core/mem/raw.odin b/core/mem/raw.odin index 2bce2d7aa..8322ace30 100644 --- a/core/mem/raw.odin +++ b/core/mem/raw.odin @@ -8,6 +8,7 @@ Raw_Cstring :: runtime.Raw_Cstring Raw_Slice :: runtime.Raw_Slice Raw_Dynamic_Array :: runtime.Raw_Dynamic_Array Raw_Map :: runtime.Raw_Map +Raw_Soa_Pointer :: runtime.Raw_Soa_Pointer Raw_Complex64 :: struct {real, imag: f32} Raw_Complex128 :: struct {real, imag: f64} diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index d1b91a829..c8f73a31b 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -700,6 +700,7 @@ Proc_Type :: struct { Pointer_Type :: struct { using node: Expr, + tag: ^Expr, pointer: tokenizer.Pos, elem: ^Expr, } diff --git a/core/odin/ast/clone.odin b/core/odin/ast/clone.odin index 400c064f5..5ec6bc335 100644 --- a/core/odin/ast/clone.odin +++ b/core/odin/ast/clone.odin @@ -286,6 +286,7 @@ clone_node :: proc(node: ^Node) -> ^Node { r.results = auto_cast clone(r.results) case ^Pointer_Type: r.elem = clone(r.elem) + r.tag = clone(r.tag) case ^Multi_Pointer_Type: r.elem = clone(r.elem) case ^Array_Type: diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index 62682004d..895fcf70d 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -186,6 +186,7 @@ Type_Kind :: enum u32le { Relative_Slice = 21, Multi_Pointer = 22, Matrix = 23, + Soa_Pointer = 24, } Type_Elems_Cap :: 4 @@ -245,6 +246,7 @@ Type :: struct { // .Relative_Slice - 2 types: 0=slice type, 1=base integer // .Multi_Pointer - 1 type: 0=element // .Matrix - 1 type: 0=element + // .Soa_Pointer - 1 type: 0=element types: Array(Type_Index), // Used by: diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 69f42b8ec..470aaccbd 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2235,7 +2235,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { return parse_call_expr(p, bd) - case "soa", "simd": + case "soa": bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name)) bd.tok = tok bd.name = name.text @@ -2244,6 +2244,20 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { #partial switch t in type.derived_expr { case ^ast.Array_Type: t.tag = bd case ^ast.Dynamic_Array_Type: t.tag = bd + case ^ast.Pointer_Type: t.tag = bd + case: + error(p, original_type.pos, "expected an array or pointer type after #%s", name.text) + } + return original_type + + case "simd": + bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name)) + bd.tok = tok + bd.name = name.text + original_type := parse_type(p) + type := ast.unparen_expr(original_type) + #partial switch t in type.derived_expr { + case ^ast.Array_Type: t.tag = bd case: error(p, original_type.pos, "expected an array type after #%s", name.text) } diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 27a83e680..794f9668a 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -34,6 +34,7 @@ Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice Type_Info_Matrix :: runtime.Type_Info_Matrix +Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value @@ -68,6 +69,7 @@ Type_Kind :: enum { Relative_Pointer, Relative_Slice, Matrix, + Soa_Pointer, } @@ -102,6 +104,7 @@ type_kind :: proc(T: typeid) -> Type_Kind { case Type_Info_Relative_Pointer: return .Relative_Pointer case Type_Info_Relative_Slice: return .Relative_Slice case Type_Info_Matrix: return .Matrix + case Type_Info_Soa_Pointer: return .Soa_Pointer } } @@ -194,6 +197,7 @@ typeid_elem :: proc(id: typeid) -> typeid { } case Type_Info_Pointer: return v.elem.id case Type_Info_Multi_Pointer: return v.elem.id + case Type_Info_Soa_Pointer: return v.elem.id case Type_Info_Array: return v.elem.id case Type_Info_Enumerated_Array: return v.elem.id case Type_Info_Slice: return v.elem.id @@ -1419,6 +1423,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_ Type_Info_Enum, Type_Info_Simd_Vector, Type_Info_Relative_Pointer, + Type_Info_Soa_Pointer, Type_Info_Matrix: return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0 diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 7be7ff812..edd4f7a26 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -68,6 +68,11 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { y := b.variant.(Type_Info_Multi_Pointer) or_return return are_types_identical(x.elem, y.elem) + case Type_Info_Soa_Pointer: + y := b.variant.(Type_Info_Soa_Pointer) or_return + return are_types_identical(x.elem, y.elem) + + case Type_Info_Procedure: y := b.variant.(Type_Info_Procedure) or_return switch { @@ -256,6 +261,11 @@ is_multi_pointer :: proc(info: ^Type_Info) -> bool { _, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer) return ok } +is_soa_pointer :: proc(info: ^Type_Info) -> bool { + if info == nil { return false } + _, ok := type_info_base(info).variant.(Type_Info_Soa_Pointer) + return ok +} is_pointer_internally :: proc(info: ^Type_Info) -> bool { if info == nil { return false } #partial switch v in info.variant { @@ -437,6 +447,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) - case Type_Info_Multi_Pointer: io.write_string(w, "[^]", &n) or_return write_type(w, info.elem, &n) or_return + case Type_Info_Soa_Pointer: + io.write_string(w, "#soa ^", &n) or_return + write_type(w, info.elem, &n) or_return case Type_Info_Procedure: io.write_string(w, "proc", &n) or_return if info.params == nil { diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 8fb3d7210..0310aff6d 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -176,6 +176,9 @@ Type_Info_Matrix :: struct { column_count: int, // Total element count = column_count * elem_stride } +Type_Info_Soa_Pointer :: struct { + elem: ^Type_Info, +} Type_Info_Flag :: enum u8 { Comparable = 0, @@ -217,6 +220,7 @@ Type_Info :: struct { Type_Info_Relative_Pointer, Type_Info_Relative_Slice, Type_Info_Matrix, + Type_Info_Soa_Pointer, }, } @@ -403,6 +407,12 @@ Raw_Cstring :: struct { data: [^]byte, } +Raw_Soa_Pointer :: struct { + data: rawptr, + index: int, +} + + /* // Defined internally by the compiler diff --git a/core/runtime/print.odin b/core/runtime/print.odin index 89c196fc2..959dad3a9 100644 --- a/core/runtime/print.odin +++ b/core/runtime/print.odin @@ -228,6 +228,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) { case Type_Info_Multi_Pointer: print_string("[^]") print_type(info.elem) + case Type_Info_Soa_Pointer: + print_string("#soa ^") + print_type(info.elem) case Type_Info_Procedure: print_string("proc") if info.params == nil { diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 86280b6cb..9d043e60a 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -320,7 +320,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) } else if (is_type_any(e->type)) { error(init_expr, "'distinct' cannot be applied to 'any'"); is_distinct = false; - } else if (is_type_simd_vector(e->type)) { + } else if (is_type_simd_vector(e->type) || is_type_soa_pointer(e->type)) { gbString str = type_to_string(e->type); error(init_expr, "'distinct' cannot be applied to '%s'", str); gb_string_free(str); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 96adde013..b2f3567ba 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2052,7 +2052,7 @@ bool check_is_not_addressable(CheckerContext *c, Operand *o) { return false; } - return o->mode != Addressing_Variable; + return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable; } void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { @@ -2069,9 +2069,6 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str); } else { switch (o->mode) { - case Addressing_SoaVariable: - error(op, "Cannot take the pointer address of '%s' as it is an indirect index of an SOA struct", str); - break; case Addressing_Constant: error(op, "Cannot take the pointer address of '%s' which is a constant", str); break; @@ -2099,7 +2096,19 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { return; } - o->type = alloc_type_pointer(o->type); + if (o->mode == Addressing_SoaVariable) { + 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); + GB_ASSERT(is_type_soa_struct(soa_type)); + o->type = alloc_type_soa_pointer(soa_type); + } else { + o->type = alloc_type_pointer(o->type); + } + } else { + o->type = alloc_type_pointer(o->type); + } switch (o->mode) { case Addressing_OptionalOk: @@ -9378,6 +9387,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type if (t->kind == Type_Pointer && !is_type_empty_union(t->Pointer.elem)) { o->mode = Addressing_Variable; o->type = t->Pointer.elem; + } 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); diff --git a/src/check_type.cpp b/src/check_type.cpp index 5d37ff208..da0a9706b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2693,9 +2693,12 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t case_ast_node(ue, UnaryExpr, e); switch (ue->op.kind) { case Token_Pointer: - *type = alloc_type_pointer(check_type(ctx, ue->expr)); - set_base_type(named_type, *type); - return true; + { + Type *elem = check_type(ctx, ue->expr); + *type = alloc_type_pointer(elem); + set_base_type(named_type, *type); + return true; + } } case_end; @@ -2721,7 +2724,24 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t elem = o.type; } - *type = alloc_type_pointer(elem); + if (pt->tag != nullptr) { + GB_ASSERT(pt->tag->kind == Ast_BasicDirective); + String name = pt->tag->BasicDirective.name.string; + if (name == "soa") { + // TODO(bill): generic #soa pointers + if (is_type_soa_struct(elem)) { + *type = alloc_type_soa_pointer(elem); + } else { + error(pt->tag, "#soa pointers require an #soa record type as the element"); + *type = alloc_type_pointer(elem); + } + } else { + error(pt->tag, "Invalid tag applied to pointer, got #%.*s", LIT(name)); + *type = alloc_type_pointer(elem); + } + } else { + *type = alloc_type_pointer(elem); + } set_base_type(named_type, *type); return true; case_end; diff --git a/src/checker.cpp b/src/checker.cpp index 874839ece..c75fc86af 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1947,6 +1947,11 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) { add_type_info_type_internal(c, bt->Matrix.elem); break; + case Type_SoaPointer: + add_type_info_type_internal(c, bt->SoaPointer.elem); + break; + + default: GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind); break; @@ -2164,6 +2169,10 @@ void add_min_dep_type_info(Checker *c, Type *t) { add_min_dep_type_info(c, bt->Matrix.elem); break; + case Type_SoaPointer: + add_min_dep_type_info(c, bt->SoaPointer.elem); + break; + default: GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind])); break; @@ -2756,6 +2765,7 @@ void init_core_type_info(Checker *c) { t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer")); t_type_info_relative_slice = find_core_type(c, str_lit("Type_Info_Relative_Slice")); 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_named_ptr = alloc_type_pointer(t_type_info_named); t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); @@ -2784,6 +2794,7 @@ void init_core_type_info(Checker *c) { t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer); t_type_info_relative_slice_ptr = alloc_type_pointer(t_type_info_relative_slice); 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); } void init_mem_allocator(Checker *c) { diff --git a/src/docs_format.cpp b/src/docs_format.cpp index b1c3c87e7..b13b8b364 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -83,6 +83,7 @@ enum OdinDocTypeKind : u32 { OdinDocType_RelativeSlice = 21, OdinDocType_MultiPointer = 22, OdinDocType_Matrix = 23, + OdinDocType_SoaPointer = 24, }; enum OdinDocTypeFlag_Basic : u32 { diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 2f531a45c..1b8e1fc34 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -532,6 +532,10 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { doc_type.kind = OdinDocType_MultiPointer; doc_type.types = odin_doc_type_as_slice(w, type->MultiPointer.elem); break; + case Type_SoaPointer: + doc_type.kind = OdinDocType_SoaPointer; + doc_type.types = odin_doc_type_as_slice(w, type->SoaPointer.elem); + break; case Type_Array: doc_type.kind = OdinDocType_Array; doc_type.elem_count_len = 1; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 07c3224de..83ee2785e 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2803,7 +2803,15 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { return {}; } - +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); + lbValue idx = lb_emit_struct_ep(p, v.addr, 1); + lb_emit_store(p, ptr, addr); + lb_emit_store(p, idx, index); + + return lb_addr_load(p, v); +} lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { ast_node(ue, UnaryExpr, expr); @@ -2842,7 +2850,17 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { lb_emit_store(p, gep1, ok); return lb_addr_load(p, res); - } if (ue_expr->kind == Ast_CompoundLit) { + } else if (is_type_soa_pointer(tv.type)) { + ast_node(ie, IndexExpr, ue_expr); + lbValue addr = lb_build_addr_ptr(p, ie->expr); + lbValue index = lb_build_expr(p, ie->index); + + if (!build_context.no_bounds_check) { + // TODO(bill): soa bounds checking + } + + return lb_make_soa_pointer(p, tv.type, addr, index); + } else if (ue_expr->kind == Ast_CompoundLit) { lbValue v = lb_build_expr(p, ue->expr); Type *type = v.type; @@ -3604,6 +3622,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { // NOTE(bill): just patch the index in place sel.index[0] = addr.swizzle.indices[sel.index[0]]; } + lbValue a = lb_addr_get_ptr(p, addr); a = lb_emit_deep_field_gep(p, a, sel); return lb_addr(a); @@ -4093,10 +4112,16 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_end; case_ast_node(de, DerefExpr, expr); - if (is_type_relative_pointer(type_of_expr(de->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;\ + return addr; + } else 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); + return lb_addr_soa_variable(ptr, idx, nullptr); } lbValue addr = lb_build_expr(p, de->expr); return lb_addr(addr); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b61439238..a83c4ebcf 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -916,7 +916,13 @@ lbValue lb_emit_load(lbProcedure *p, lbValue value) { Type *t = vt->MultiPointer.elem; LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); return lbValue{v, t}; + } else if (is_type_soa_pointer(value.type)) { + lbValue ptr = lb_emit_struct_ev(p, value, 0); + lbValue idx = lb_emit_struct_ev(p, value, 1); + lbAddr addr = lb_addr_soa_variable(ptr, idx, nullptr); + return lb_addr_load(p, addr); } + GB_ASSERT(is_type_pointer(value.type)); Type *t = type_deref(value.type); LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); @@ -2055,6 +2061,15 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { m->internal_type_level += 1; return t; } + + case Type_SoaPointer: + { + unsigned field_count = 2; + LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count); + fields[0] = LLVMPointerType(lb_type(m, type->Pointer.elem), 0); + fields[1] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size); + return LLVMStructTypeInContext(ctx, fields, field_count, false); + } } diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 2e7b2788a..5e7fcc399 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -57,6 +57,7 @@ lbValue lb_typeid(lbModule *m, Type *type) { case Type_SimdVector: kind = Typeid_Simd_Vector; break; case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; case Type_RelativeSlice: kind = Typeid_Relative_Slice; break; + case Type_SoaPointer: kind = Typeid_SoaPointer; break; } if (is_type_cstring(type)) { @@ -445,6 +446,20 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lb_emit_store(p, tag, res); break; } + case Type_SoaPointer: { + tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_soa_pointer_ptr); + lbValue gep = lb_get_type_info_ptr(m, t->SoaPointer.elem); + + LLVMValueRef vals[1] = { + gep.value, + }; + + lbValue res = {}; + res.type = type_deref(tag.type); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); + lb_emit_store(p, tag, res); + break; + } case Type_Array: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_array_ptr); i64 ez = type_size_of(t->Array.elem); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index bbacce7a2..f1c74925e 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1007,6 +1007,11 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { case 0: result_type = t->RelativeSlice.base_integer; break; case 1: result_type = t->RelativeSlice.base_integer; break; } + } else if (is_type_soa_pointer(t)) { + switch (index) { + case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break; + case 1: result_type = t_int; break; + } } else { GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index); } @@ -1137,6 +1142,13 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { result_type = t->Array.elem; break; + case Type_SoaPointer: + switch (index) { + case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break; + case 1: result_type = t_int; break; + } + break; + default: GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s.type), index); break; @@ -1164,7 +1176,28 @@ lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) { } type = core_type(type); - if (is_type_quaternion(type)) { + if (type->kind == Type_SoaPointer) { + lbValue addr = lb_emit_struct_ep(p, e, 0); + lbValue index = lb_emit_struct_ep(p, e, 1); + addr = lb_emit_load(p, addr); + index = lb_emit_load(p, index); + + i32 first_index = sel.index[0]; + Selection sub_sel = sel; + sub_sel.index.data += 1; + sub_sel.index.count -= 1; + + lbValue arr = lb_emit_struct_ep(p, addr, first_index); + + Type *t = base_type(type_deref(addr.type)); + GB_ASSERT(is_type_soa_struct(t)); + + if (t->Struct.soa_kind == StructSoa_Fixed) { + e = lb_emit_array_ep(p, arr, index); + } else { + e = lb_emit_ptr_offset(p, lb_emit_load(p, arr), index); + } + } else if (is_type_quaternion(type)) { e = lb_emit_struct_ep(p, e, index); } else if (is_type_raw_union(type)) { type = get_struct_field_type(type, index); diff --git a/src/parser.cpp b/src/parser.cpp index ac3acef8a..9a5531289 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -356,6 +356,7 @@ Ast *clone_ast(Ast *node) { break; case Ast_PointerType: n->PointerType.type = clone_ast(n->PointerType.type); + n->PointerType.tag = clone_ast(n->PointerType.tag); break; case Ast_MultiPointerType: n->MultiPointerType.type = clone_ast(n->MultiPointerType.type); @@ -2167,10 +2168,11 @@ Ast *parse_operand(AstFile *f, bool lhs) { Ast *original_type = parse_type(f); Ast *type = unparen_expr(original_type); switch (type->kind) { - case Ast_ArrayType: type->ArrayType.tag = tag; break; + case Ast_ArrayType: type->ArrayType.tag = tag; break; case Ast_DynamicArrayType: type->DynamicArrayType.tag = tag; break; + case Ast_PointerType: type->PointerType.tag = tag; break; default: - syntax_error(type, "Expected an array type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind])); + syntax_error(type, "Expected an array or pointer type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind])); break; } return original_type; diff --git a/src/parser.hpp b/src/parser.hpp index 156991e24..bfdae58a5 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -650,7 +650,8 @@ AST_KIND(_TypeBegin, "", bool) \ }) \ AST_KIND(PointerType, "pointer type", struct { \ Token token; \ - Ast *type; \ + Ast *type; \ + Ast *tag; \ }) \ AST_KIND(RelativeType, "relative type", struct { \ Ast *tag; \ diff --git a/src/types.cpp b/src/types.cpp index 5f112ce09..cba27fd6f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -278,7 +278,8 @@ struct TypeProc { Type *generic_row_count; \ Type *generic_column_count; \ i64 stride_in_bytes; \ - }) + }) \ + TYPE_KIND(SoaPointer, struct { Type *elem; }) enum TypeKind { @@ -350,6 +351,7 @@ enum Typeid_Kind : u8 { Typeid_Relative_Pointer, Typeid_Relative_Slice, Typeid_Matrix, + Typeid_SoaPointer, }; // IMPORTANT NOTE(bill): This must match the same as the in core.odin @@ -644,6 +646,7 @@ 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_slice = nullptr; gb_global Type *t_type_info_matrix = nullptr; +gb_global Type *t_type_info_soa_pointer = nullptr; gb_global Type *t_type_info_named_ptr = nullptr; gb_global Type *t_type_info_integer_ptr = nullptr; @@ -672,6 +675,7 @@ 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_slice_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_allocator = nullptr; gb_global Type *t_allocator_ptr = nullptr; @@ -735,6 +739,7 @@ Type * bit_set_to_int(Type *t); bool are_types_identical(Type *x, Type *y); bool is_type_pointer(Type *t); +bool is_type_soa_pointer(Type *t); bool is_type_proc(Type *t); bool is_type_slice(Type *t); bool is_type_integer(Type *t); @@ -917,6 +922,13 @@ Type *alloc_type_multi_pointer(Type *elem) { return t; } +Type *alloc_type_soa_pointer(Type *elem) { + Type *t = alloc_type(Type_SoaPointer); + t->SoaPointer.elem = elem; + return t; +} + + Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = nullptr) { if (generic_count != nullptr) { Type *t = alloc_type(Type_Array); @@ -1109,11 +1121,17 @@ Type *type_deref(Type *t) { if (bt == nullptr) { return nullptr; } - if (bt->kind == Type_Pointer) { + switch (bt->kind) { + case Type_Pointer: return bt->Pointer.elem; - } - if (bt->kind == Type_RelativePointer) { + case Type_RelativePointer: return type_deref(bt->RelativePointer.pointer_type); + case Type_SoaPointer: + { + Type *elem = base_type(bt->SoaPointer.elem); + GB_ASSERT(elem->kind == Type_Struct && elem->Struct.soa_kind != StructSoa_None); + return elem->Struct.soa_elem; + } } } return t; @@ -1327,6 +1345,10 @@ bool is_type_pointer(Type *t) { } return t->kind == Type_Pointer; } +bool is_type_soa_pointer(Type *t) { + t = base_type(t); + return t->kind == Type_SoaPointer; +} bool is_type_multi_pointer(Type *t) { t = base_type(t); return t->kind == Type_MultiPointer; @@ -1804,7 +1826,7 @@ bool is_type_dereferenceable(Type *t) { if (is_type_rawptr(t)) { return false; } - return is_type_pointer(t); + return is_type_pointer(t) || is_type_soa_pointer(t); } @@ -2079,6 +2101,9 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) { case Type_Pointer: return is_type_polymorphic(t->Pointer.elem, or_specialized); + case Type_SoaPointer: + return is_type_polymorphic(t->SoaPointer.elem, or_specialized); + case Type_EnumeratedArray: if (is_type_polymorphic(t->EnumeratedArray.index, or_specialized)) { return true; @@ -2196,6 +2221,7 @@ bool type_has_nil(Type *t) { case Type_Slice: case Type_Proc: case Type_Pointer: + case Type_SoaPointer: case Type_MultiPointer: case Type_DynamicArray: case Type_Map: @@ -2262,6 +2288,8 @@ bool is_type_comparable(Type *t) { return true; case Type_Pointer: return true; + case Type_SoaPointer: + return true; case Type_MultiPointer: return true; case Type_Enum: @@ -2335,6 +2363,7 @@ bool is_type_simple_compare(Type *t) { case Type_Pointer: case Type_MultiPointer: + case Type_SoaPointer: case Type_Proc: case Type_BitSet: return true; @@ -2558,6 +2587,12 @@ bool are_types_identical_internal(Type *x, Type *y, bool check_tuple_names) { } break; + case Type_SoaPointer: + if (y->kind == Type_SoaPointer) { + return are_types_identical(x->SoaPointer.elem, y->SoaPointer.elem); + } + break; + case Type_Named: if (y->kind == Type_Named) { return x->Named.type_name == y->Named.type_name; @@ -3475,6 +3510,9 @@ i64 type_align_of_internal(Type *t, TypePath *path) { return type_align_of_internal(t->RelativePointer.base_integer, path); case Type_RelativeSlice: return type_align_of_internal(t->RelativeSlice.base_integer, path); + + case Type_SoaPointer: + return build_context.word_size; } // return gb_clamp(next_pow2(type_size_of(t)), 1, build_context.max_align); @@ -3580,6 +3618,9 @@ i64 type_size_of_internal(Type *t, TypePath *path) { case Type_MultiPointer: return build_context.word_size; + case Type_SoaPointer: + return build_context.word_size*2; + case Type_Array: { i64 count, align, size, alignment; count = t->Array.count; @@ -4017,6 +4058,11 @@ gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) { str = write_type_to_string(str, type->Pointer.elem); break; + case Type_SoaPointer: + str = gb_string_appendc(str, "#soa ^"); + str = write_type_to_string(str, type->SoaPointer.elem); + break; + case Type_MultiPointer: str = gb_string_appendc(str, "[^]"); str = write_type_to_string(str, type->Pointer.elem); -- cgit v1.2.3 From cb0a59bb2cfdeb971e88f329f07783ba1f93a5c9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 9 Aug 2022 15:36:18 +0100 Subject: Eliminate use of LLVMGetElementType for pointers --- core/log/log_allocator.odin | 31 +++++-- src/llvm_abi.cpp | 10 ++- src/llvm_backend.cpp | 4 +- src/llvm_backend.hpp | 5 +- src/llvm_backend_expr.cpp | 2 +- src/llvm_backend_general.cpp | 210 +++++++++++++++++++++++-------------------- src/llvm_backend_proc.cpp | 14 ++- src/llvm_backend_type.cpp | 10 ++- src/llvm_backend_utility.cpp | 4 +- 9 files changed, 164 insertions(+), 126 deletions(-) (limited to 'src') diff --git a/core/log/log_allocator.odin b/core/log/log_allocator.odin index eb7a6b377..997bd1a68 100644 --- a/core/log/log_allocator.odin +++ b/core/log/log_allocator.odin @@ -29,6 +29,8 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, runtime.Allocator_Error) { la := (^Log_Allocator)(allocator_data) + padding := " " if la.prefix != "" else "" + if !la.locked { la.locked = true defer la.locked = false @@ -38,7 +40,7 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, logf( level=la.level, fmt_str = "%s%s>>> ALLOCATOR(mode=.Alloc, size=%d, alignment=%d)", - args = {la.prefix, " " if la.prefix != "" else "", size, alignment}, + args = {la.prefix, padding, size, alignment}, location = location, ) case .Free: @@ -46,14 +48,14 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, logf( level=la.level, fmt_str = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)", - args = {la.prefix, " " if la.prefix != "" else "", old_memory, old_size}, + args = {la.prefix, padding, old_memory, old_size}, location = location, ) } else { logf( level=la.level, fmt_str = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)", - args = {la.prefix, " " if la.prefix != "" else "", old_memory}, + args = {la.prefix, padding, old_memory}, location = location, ) } @@ -61,32 +63,45 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, logf( level=la.level, fmt_str = "%s%s<<< ALLOCATOR(mode=.Free_All)", - args = {la.prefix, " " if la.prefix != "" else ""}, + args = {la.prefix, padding}, location = location, ) case .Resize: logf( level=la.level, fmt_str = "%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%d, size=%d, alignment=%d)", - args = {la.prefix, " " if la.prefix != "" else "", old_memory, old_size, size, alignment}, + args = {la.prefix, padding, old_memory, old_size, size, alignment}, location = location, ) case .Query_Features: logf( level=la.level, fmt_str = "%s%ALLOCATOR(mode=.Query_Features)", - args = {la.prefix, " " if la.prefix != "" else ""}, + args = {la.prefix, padding}, location = location, ) case .Query_Info: logf( level=la.level, fmt_str = "%s%ALLOCATOR(mode=.Query_Info)", - args = {la.prefix, " " if la.prefix != "" else ""}, + args = {la.prefix, padding}, location = location, ) } } - return la.allocator.procedure(la.allocator.data, mode, size, alignment, old_memory, old_size, location) + data, err := la.allocator.procedure(la.allocator.data, mode, size, alignment, old_memory, old_size, location) + if !la.locked { + la.locked = true + defer la.locked = false + if err != nil { + logf( + level=la.level, + fmt_str = "%s%ALLOCATOR ERROR=%v", + args = {la.prefix, padding, error}, + location = location, + ) + } + } + return data, err } \ No newline at end of file diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index b22a839b3..2ff55c79b 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -62,7 +62,7 @@ bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) { return LLVMGetTypeKind(type) == kind; } -LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) { +LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) { unsigned arg_count = cast(unsigned)ft->args.count; unsigned offset = 0; @@ -108,10 +108,16 @@ LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) { } unsigned total_arg_count = arg_index; LLVMTypeRef func_type = LLVMFunctionType(ret, args, total_arg_count, is_var_arg); - return LLVMPointerType(func_type, 0); + return func_type; } +// LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) { +// LLVMTypeRef func_type = lb_function_type_to_llvm_raw(ft, is_var_arg); +// return LLVMPointerType(func_type, 0); +// } + + void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) { if (ft == nullptr) { return; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index bcd11c8ea..6ee1541d6 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -739,11 +739,11 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start lb_begin_procedure_body(p); if (startup_type_info) { - LLVMBuildCall2(p->builder, lb_llvm_get_pointer_type(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); + LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, startup_type_info->type), startup_type_info->value, nullptr, 0, ""); } if (objc_names) { - LLVMBuildCall2(p->builder, lb_llvm_get_pointer_type(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, ""); + LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, ""); } for_array(i, global_variables) { diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 05dfb3734..149f1e711 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -127,6 +127,7 @@ struct lbModule { AstPackage *pkg; // associated PtrMap types; + PtrMap func_raw_types; PtrMap struct_field_remapping; // Key: LLVMTypeRef or Type * i32 internal_type_level; @@ -330,7 +331,8 @@ lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_b void lb_end_procedure(lbProcedure *p); -LLVMTypeRef lb_type(lbModule *m, Type *type); +LLVMTypeRef lb_type(lbModule *m, Type *type); +LLVMTypeRef llvm_get_element_type(LLVMTypeRef type); lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false); @@ -343,7 +345,6 @@ lbValue lb_const_int(lbModule *m, Type *type, u64 value); lbAddr lb_addr(lbValue addr); Type *lb_addr_type(lbAddr const &addr); -LLVMTypeRef lb_llvm_get_pointer_type(LLVMTypeRef type); LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val); void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value); lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 4ae46aeb8..7568f975e 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3345,7 +3345,7 @@ lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { default: GB_PANIC("Unhandled inline asm dialect"); break; } - LLVMTypeRef func_type = lb_llvm_get_pointer_type(lb_type(p->module, t)); + LLVMTypeRef func_type = lb_type_internal_for_procedures_raw(p->module, t); LLVMValueRef the_asm = llvm_get_inline_asm(func_type, asm_string, constraints_string, ia->has_side_effects, ia->has_side_effects, dialect); GB_ASSERT(the_asm != nullptr); return {the_asm, t}; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b212ee8b8..eb5cf371c 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -56,6 +56,7 @@ void lb_init_module(lbModule *m, Checker *c) { gbAllocator a = heap_allocator(); map_init(&m->types, a); + map_init(&m->func_raw_types, a); map_init(&m->struct_field_remapping, a); map_init(&m->values, a); map_init(&m->soa_values, a); @@ -1416,6 +1417,116 @@ String lb_get_entity_name(lbModule *m, Entity *e, String default_name) { } +LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) { + Type *original_type = type; + type = base_type(original_type); + GB_ASSERT(type->kind == Type_Proc); + + LLVMTypeRef *found = map_get(&m->func_raw_types, type); + if (found) { + return *found; + } + + unsigned param_count = 0; + if (type->Proc.calling_convention == ProcCC_Odin) { + param_count += 1; + } + + if (type->Proc.param_count != 0) { + GB_ASSERT(type->Proc.params->kind == Type_Tuple); + for_array(i, type->Proc.params->Tuple.variables) { + Entity *e = type->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + if (e->flags & EntityFlag_CVarArg) { + continue; + } + param_count += 1; + } + } + m->internal_type_level += 1; + defer (m->internal_type_level -= 1); + + LLVMTypeRef ret = nullptr; + LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count); + if (type->Proc.result_count != 0) { + Type *single_ret = reduce_tuple_to_single_type(type->Proc.results); + ret = lb_type(m, single_ret); + if (ret != nullptr) { + if (is_type_boolean(single_ret) && + is_calling_convention_none(type->Proc.calling_convention) && + type_size_of(single_ret) <= 1) { + ret = LLVMInt1TypeInContext(m->ctx); + } + } + } + + unsigned param_index = 0; + if (type->Proc.param_count != 0) { + GB_ASSERT(type->Proc.params->kind == Type_Tuple); + for_array(i, type->Proc.params->Tuple.variables) { + Entity *e = type->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + if (e->flags & EntityFlag_CVarArg) { + continue; + } + Type *e_type = reduce_tuple_to_single_type(e->type); + + LLVMTypeRef param_type = nullptr; + if (e->flags & EntityFlag_ByPtr) { + param_type = lb_type(m, alloc_type_pointer(e_type)); + } else if (is_type_boolean(e_type) && + type_size_of(e_type) <= 1) { + param_type = LLVMInt1TypeInContext(m->ctx); + } else { + if (is_type_proc(e_type)) { + param_type = lb_type(m, t_rawptr); + } else { + param_type = lb_type(m, e_type); + } + } + + params[param_index++] = param_type; + } + } + if (param_index < param_count) { + params[param_index++] = lb_type(m, t_rawptr); + } + GB_ASSERT(param_index == param_count); + + lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention); + { + for_array(j, ft->args) { + auto arg = ft->args[j]; + GB_ASSERT_MSG(LLVMGetTypeContext(arg.type) == ft->ctx, + "\n\t%s %td/%td" + "\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", + LLVMPrintTypeToString(arg.type), + j, ft->args.count, + LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext()); + } + GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx, + "\n\t%s" + "\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", + LLVMPrintTypeToString(ft->ret.type), + LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext()); + } + + map_set(&m->function_type_map, type, ft); + LLVMTypeRef new_abi_fn_type = lb_function_type_to_llvm_raw(ft, type->Proc.c_vararg); + + GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx, + "\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", + LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext()); + + map_set(&m->func_raw_types, type, new_abi_fn_type); + + return new_abi_fn_type; + +} LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { LLVMContextRef ctx = m->ctx; i64 size = type_size_of(type); // Check size @@ -1919,103 +2030,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough? return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0); } else { - unsigned param_count = 0; - if (type->Proc.calling_convention == ProcCC_Odin) { - param_count += 1; - } - - if (type->Proc.param_count != 0) { - GB_ASSERT(type->Proc.params->kind == Type_Tuple); - for_array(i, type->Proc.params->Tuple.variables) { - Entity *e = type->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - if (e->flags & EntityFlag_CVarArg) { - continue; - } - param_count += 1; - } - } - m->internal_type_level += 1; - defer (m->internal_type_level -= 1); - - LLVMTypeRef ret = nullptr; - LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count); - if (type->Proc.result_count != 0) { - Type *single_ret = reduce_tuple_to_single_type(type->Proc.results); - ret = lb_type(m, single_ret); - if (ret != nullptr) { - if (is_type_boolean(single_ret) && - is_calling_convention_none(type->Proc.calling_convention) && - type_size_of(single_ret) <= 1) { - ret = LLVMInt1TypeInContext(m->ctx); - } - } - } - - unsigned param_index = 0; - if (type->Proc.param_count != 0) { - GB_ASSERT(type->Proc.params->kind == Type_Tuple); - for_array(i, type->Proc.params->Tuple.variables) { - Entity *e = type->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - if (e->flags & EntityFlag_CVarArg) { - continue; - } - Type *e_type = reduce_tuple_to_single_type(e->type); - - LLVMTypeRef param_type = nullptr; - if (e->flags & EntityFlag_ByPtr) { - param_type = lb_type(m, alloc_type_pointer(e_type)); - } else if (is_type_boolean(e_type) && - type_size_of(e_type) <= 1) { - param_type = LLVMInt1TypeInContext(m->ctx); - } else { - if (is_type_proc(e_type)) { - param_type = lb_type(m, t_rawptr); - } else { - param_type = lb_type(m, e_type); - } - } - - params[param_index++] = param_type; - } - } - if (param_index < param_count) { - params[param_index++] = lb_type(m, t_rawptr); - } - GB_ASSERT(param_index == param_count); - - lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention); - { - for_array(j, ft->args) { - auto arg = ft->args[j]; - GB_ASSERT_MSG(LLVMGetTypeContext(arg.type) == ft->ctx, - "\n\t%s %td/%td" - "\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", - LLVMPrintTypeToString(arg.type), - j, ft->args.count, - LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext()); - } - GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx, - "\n\t%s" - "\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", - LLVMPrintTypeToString(ft->ret.type), - LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext()); - } - - map_set(&m->function_type_map, type, ft); - LLVMTypeRef new_abi_fn_ptr_type = lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg); - LLVMTypeRef new_abi_fn_type = lb_llvm_get_pointer_type(new_abi_fn_ptr_type); - - GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx, - "\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p", - LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext()); - - return new_abi_fn_ptr_type; + LLVMTypeRef proc_raw_type = lb_type_internal_for_procedures_raw(m, type); + return LLVMPointerType(proc_raw_type, 0); } break; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 756a93db7..392ff14c2 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -129,8 +129,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) } char *c_link_name = alloc_cstring(permanent_allocator(), p->name); - LLVMTypeRef func_ptr_type = lb_type(m, p->type); - LLVMTypeRef func_type = lb_llvm_get_pointer_type(func_ptr_type); + LLVMTypeRef func_type = lb_get_procedure_raw_type(m, p->type); p->value = LLVMAddFunction(m->mod, c_link_name, func_type); @@ -354,8 +353,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type char *c_link_name = alloc_cstring(permanent_allocator(), p->name); - LLVMTypeRef func_ptr_type = lb_type(m, p->type); - LLVMTypeRef func_type = lb_llvm_get_pointer_type(func_ptr_type); + LLVMTypeRef func_type = lb_get_procedure_raw_type(m, p->type); p->value = LLVMAddFunction(m->mod, c_link_name, func_type); @@ -753,12 +751,12 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, GB_ASSERT(curr_block != p->decl_block->block); { - LLVMTypeRef ftp = lb_type(p->module, value.type); + LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, value.type); + LLVMTypeRef ftp = LLVMPointerType(fnp, 0); LLVMValueRef fn = value.value; if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) { fn = LLVMBuildPointerCast(p->builder, fn, ftp, ""); } - LLVMTypeRef fnp = lb_llvm_get_pointer_type(LLVMTypeOf(fn)); GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp)); { @@ -2723,7 +2721,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, { Type *param_types[2] = {t_u32, t_u32}; Type *type = alloc_type_proc_from_types(param_types, gb_count_of(param_types), tv.type, false, ProcCC_None); - LLVMTypeRef func_type = lb_llvm_get_pointer_type(lb_type(p->module, type)); + LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type); LLVMValueRef the_asm = llvm_get_inline_asm( func_type, str_lit("cpuid"), @@ -2743,7 +2741,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_x86_xgetbv: { Type *type = alloc_type_proc_from_types(&t_u32, 1, tv.type, false, ProcCC_None); - LLVMTypeRef func_type = lb_llvm_get_pointer_type(lb_type(p->module, type)); + LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type); LLVMValueRef the_asm = llvm_get_inline_asm( func_type, str_lit("xgetbv"), diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 10cae9e6c..ba4135901 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -130,12 +130,16 @@ lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { return res; } -// The use of this method needs to be eliminated. -LLVMTypeRef lb_llvm_get_pointer_type(LLVMTypeRef type) -{ +// NOTE: The use of this method needs to be eliminated for pointers. +LLVMTypeRef llvm_get_element_type(LLVMTypeRef type) { return LLVMGetElementType(type); } +LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) { + return lb_type_internal_for_procedures_raw(m, type); +} + + lbValue lb_type_info_member_types_offset(lbProcedure *p, isize count) { GB_ASSERT(p->module == &p->module->gen->default_module); lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_types.addr, lb_global_type_info_member_types_index); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index b6589a080..665ba1553 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -96,9 +96,7 @@ LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValu args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, ""); // We always get the function pointer type rather than the function and there is apparently no way around that? - LLVMTypeRef type = lb_type(p->module, pr.type); - - type = lb_llvm_get_pointer_type(type); + LLVMTypeRef type = lb_type_internal_for_procedures_raw(p->module, pr.type); return LLVMBuildCall2(p->builder, type, pr.value, args, gb_count_of(args), ""); } -- cgit v1.2.3 From ff94c605e01a20c44e34ebd8469b9ceffbed6f59 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 9 Aug 2022 18:08:30 +0100 Subject: Minor change to `lb_emit_store` for storing nil to procedure variables --- src/llvm_backend_general.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index eb5cf371c..58de9d36a 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -853,7 +853,9 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { if (LLVMIsNull(value.value)) { LLVMTypeRef src_t = llvm_addr_type(p->module, ptr); - if (lb_sizeof(src_t) <= lb_max_zero_init_size()) { + if (is_type_proc(a)) { + LLVMBuildStore(p->builder, LLVMConstNull(llvm_get_element_type(LLVMTypeOf(ptr.value))), ptr.value); + } else if (lb_sizeof(src_t) <= lb_max_zero_init_size()) { LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value); } else { lb_mem_zero_ptr(p, ptr.value, a, 1); -- cgit v1.2.3 From 4c3281b3f2f900eb810637e8c62165aad9d6a8f9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 9 Aug 2022 18:09:26 +0100 Subject: Disallow Early CSE on `-debug` builds --- src/llvm_backend_opt.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index 6b80b21d6..e2f51b868 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -62,7 +62,9 @@ void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimiz LLVMAddPromoteMemoryToRegisterPass(fpm); LLVMAddMergedLoadStoreMotionPass(fpm); LLVM_ADD_CONSTANT_VALUE_PASS(fpm); - LLVMAddEarlyCSEPass(fpm); + if (!build_context.ODIN_DEBUG) { + LLVMAddEarlyCSEPass(fpm); + } } } -- cgit v1.2.3 From cfc372387923372c011ebaa97cd80461d68e2089 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 9 Aug 2022 21:12:31 +0100 Subject: Remove other uses of LLVMGetElementType on pointer types --- src/llvm_backend_general.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 58de9d36a..af7673a69 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -854,7 +854,9 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { if (LLVMIsNull(value.value)) { LLVMTypeRef src_t = llvm_addr_type(p->module, ptr); if (is_type_proc(a)) { - LLVMBuildStore(p->builder, LLVMConstNull(llvm_get_element_type(LLVMTypeOf(ptr.value))), ptr.value); + LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr); + LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0); + LLVMBuildStore(p->builder, LLVMConstNull(rawptr_type), LLVMBuildBitCast(p->builder, ptr.value, rawptr_ptr_type, "")); } else if (lb_sizeof(src_t) <= lb_max_zero_init_size()) { LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value); } else { @@ -889,9 +891,11 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { // NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be // stored as regular pointer with no procedure information - LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value)); - LLVMValueRef v = LLVMBuildPointerCast(p->builder, value.value, src_t, ""); - LLVMBuildStore(p->builder, v, ptr.value); + LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr); + LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0); + LLVMBuildStore(p->builder, + LLVMBuildPointerCast(p->builder, value.value, rawptr_type, ""), + LLVMBuildPointerCast(p->builder, ptr.value, rawptr_ptr_type, "")); } else { Type *ca = core_type(a); if (ca->kind == Type_Basic || ca->kind == Type_Proc) { -- cgit v1.2.3 From 065526037876143c91dbbfaeb44666a474ff93c0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 9 Aug 2022 21:13:52 +0100 Subject: Comment out a bit of code in `lb_is_const_or_global` --- src/llvm_backend_const.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 8d910cf24..954778bb6 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -10,11 +10,12 @@ bool lb_is_const(lbValue value) { return false; } -// TODO remove use of LLVMGetElementType bool lb_is_const_or_global(lbValue value) { if (lb_is_const(value)) { return true; } + // TODO remove use of LLVMGetElementType + #if 0 if (LLVMGetValueKind(value.value) == LLVMGlobalVariableValueKind) { LLVMTypeRef t = LLVMGetElementType(LLVMTypeOf(value.value)); if (!lb_is_type_kind(t, LLVMPointerTypeKind)) { @@ -23,6 +24,7 @@ bool lb_is_const_or_global(lbValue value) { LLVMTypeRef elem = LLVMGetElementType(t); return lb_is_type_kind(elem, LLVMFunctionTypeKind); } + #endif return false; } -- cgit v1.2.3 From 812823cad83d76987ee6b924b70427fbffe34f02 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 9 Aug 2022 21:17:32 +0100 Subject: Wrap all `LLVMGetElementType` uses --- src/llvm_abi.cpp | 16 ++++++++-------- src/llvm_backend.hpp | 3 +++ src/llvm_backend_general.cpp | 11 +++++++++++ src/llvm_backend_type.cpp | 5 ----- src/llvm_backend_utility.cpp | 8 ++++---- 5 files changed, 26 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 2ff55c79b..2ee8dc673 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -223,7 +223,7 @@ i64 lb_sizeof(LLVMTypeRef type) { break; case LLVMArrayTypeKind: { - LLVMTypeRef elem = LLVMGetElementType(type); + LLVMTypeRef elem = OdinLLVMGetArrayElementType(type); i64 elem_size = lb_sizeof(elem); i64 count = LLVMGetArrayLength(type); i64 size = count * elem_size; @@ -235,7 +235,7 @@ i64 lb_sizeof(LLVMTypeRef type) { return 8; case LLVMVectorTypeKind: { - LLVMTypeRef elem = LLVMGetElementType(type); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(type); i64 elem_size = lb_sizeof(elem); i64 count = LLVMGetVectorSize(type); i64 size = count * elem_size; @@ -283,14 +283,14 @@ i64 lb_alignof(LLVMTypeRef type) { } break; case LLVMArrayTypeKind: - return lb_alignof(LLVMGetElementType(type)); + return lb_alignof(OdinLLVMGetArrayElementType(type)); case LLVMX86_MMXTypeKind: return 8; case LLVMVectorTypeKind: { // TODO(bill): This appears to be correct but LLVM isn't necessarily "great" with regards to documentation - LLVMTypeRef elem = LLVMGetElementType(type); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(type); i64 elem_size = lb_sizeof(elem); i64 count = LLVMGetVectorSize(type); i64 size = count * elem_size; @@ -793,7 +793,7 @@ namespace lbAbiAmd64SysV { case LLVMArrayTypeKind: { i64 len = LLVMGetArrayLength(t); - LLVMTypeRef elem = LLVMGetElementType(t); + LLVMTypeRef elem = OdinLLVMGetArrayElementType(t); i64 elem_sz = lb_sizeof(elem); for (i64 i = 0; i < len; i++) { classify_with(elem, cls, ix, off + i*elem_sz); @@ -803,7 +803,7 @@ namespace lbAbiAmd64SysV { case LLVMVectorTypeKind: { i64 len = LLVMGetVectorSize(t); - LLVMTypeRef elem = LLVMGetElementType(t); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(t); i64 elem_sz = lb_sizeof(elem); LLVMTypeKind elem_kind = LLVMGetTypeKind(elem); RegClass reg = RegClass_NoClass; @@ -913,7 +913,7 @@ namespace lbAbiArm64 { if (len == 0) { return false; } - LLVMTypeRef elem = LLVMGetElementType(type); + LLVMTypeRef elem = OdinLLVMGetArrayElementType(type); LLVMTypeRef base_type = nullptr; unsigned member_count = 0; if (is_homogenous_aggregate(c, elem, &base_type, &member_count)) { @@ -1129,7 +1129,7 @@ namespace lbAbiWasm { } if (sz <= MAX_DIRECT_STRUCT_SIZE) { if (kind == LLVMArrayTypeKind) { - if (is_basic_register_type(LLVMGetElementType(type))) { + if (is_basic_register_type(OdinLLVMGetArrayElementType(type))) { return true; } } else if (kind == LLVMStructTypeKind) { diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 149f1e711..4a056e915 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -507,6 +507,9 @@ i64 lb_max_zero_init_size(void) { return cast(i64)(4*build_context.word_size); } +LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type); +LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type); + #define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" #define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" #define LB_TYPE_INFO_DATA_NAME "__$type_info_data" diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index af7673a69..7138ac191 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2293,6 +2293,17 @@ void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *fals } +gb_inline LLVMTypeRef OdinLLVMGetInternalElementType(LLVMTypeRef type) { + return LLVMGetElementType(type); +} +LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type) { + GB_ASSERT(lb_is_type_kind(type, LLVMArrayTypeKind)); + return OdinLLVMGetInternalElementType(type); +} +LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type) { + GB_ASSERT(lb_is_type_kind(type, LLVMVectorTypeKind)); + return OdinLLVMGetInternalElementType(type); +} LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index ba4135901..3d20b3d72 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -130,11 +130,6 @@ lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { return res; } -// NOTE: The use of this method needs to be eliminated for pointers. -LLVMTypeRef llvm_get_element_type(LLVMTypeRef type) { - return LLVMGetElementType(type); -} - LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) { return lb_type_internal_for_procedures_raw(m, type); } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 665ba1553..3485c8436 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1651,7 +1651,7 @@ LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef val LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) { LLVMTypeRef type = LLVMTypeOf(value); GB_ASSERT(LLVMGetTypeKind(type) == LLVMVectorTypeKind); - LLVMTypeRef elem = LLVMGetElementType(type); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(type); unsigned len = LLVMGetVectorSize(type); if (len == 0) { return LLVMConstNull(type); @@ -1727,7 +1727,7 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) { LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) { GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b)); - LLVMTypeRef elem = LLVMGetElementType(LLVMTypeOf(a)); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a)); if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) { return LLVMBuildAdd(p->builder, a, b, ""); @@ -1738,7 +1738,7 @@ LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) { LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) { GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b)); - LLVMTypeRef elem = LLVMGetElementType(LLVMTypeOf(a)); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a)); if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) { return LLVMBuildMul(p->builder, a, b, ""); @@ -1758,7 +1758,7 @@ LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, GB_ASSERT(t == LLVMTypeOf(c)); GB_ASSERT(LLVMGetTypeKind(t) == LLVMVectorTypeKind); - LLVMTypeRef elem = LLVMGetElementType(t); + LLVMTypeRef elem = OdinLLVMGetVectorElementType(t); bool is_possible = false; -- cgit v1.2.3 From 84f9fb706b90d97e7e52819af8388f64e38970e3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 10 Aug 2022 11:36:25 +0100 Subject: General clean up of LLVM*GEP2 code --- src/llvm_backend.hpp | 5 +-- src/llvm_backend_general.cpp | 39 ++++++++++++++++++++++ src/llvm_backend_type.cpp | 78 ++++++++++++++------------------------------ src/llvm_backend_utility.cpp | 39 ++++++++++------------ 4 files changed, 84 insertions(+), 77 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 4a056e915..79f0f37e7 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -357,8 +357,9 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr); lbAddr lb_build_addr(lbProcedure *p, Ast *expr); void lb_build_stmt_list(lbProcedure *p, Array const &stmts); -lbValue lb_build_gep(lbProcedure *p, lbValue const &value, i32 index) ; - +lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index); +lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index); +lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index); lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index); lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index); lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 7138ac191..082163b2f 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -212,6 +212,45 @@ void lb_loop_end(lbProcedure *p, lbLoopData const &data) { } +// This emits a GEP at 0, index +lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index) { + GB_ASSERT(is_type_pointer(value.type)); + Type *type = type_deref(value.type); + + LLVMValueRef indices[2] = { + LLVMConstInt(lb_type(p->module, t_int), 0, false), + LLVMConstInt(lb_type(p->module, t_int), cast(unsigned long long)index, false), + }; + LLVMTypeRef llvm_type = lb_type(p->module, type); + lbValue res = {}; + Type *ptr = base_array_type(type); + res.type = alloc_type_pointer(ptr); + if (LLVMIsConstant(value.value)) { + res.value = LLVMConstGEP2(llvm_type, value.value, indices, gb_count_of(indices)); + } else { + res.value = LLVMBuildGEP2(p->builder, llvm_type, value.value, indices, gb_count_of(indices), ""); + } + return res; +} +// This emits a GEP at 0, index +lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index) { + GB_ASSERT(is_type_pointer(value.type)); + GB_ASSERT(LLVMIsConstant(value.value)); + Type *type = type_deref(value.type); + + LLVMValueRef indices[2] = { + LLVMConstInt(lb_type(m, t_int), 0, false), + LLVMConstInt(lb_type(m, t_int), cast(unsigned long long)index, false), + }; + lbValue res = {}; + Type *ptr = base_array_type(type); + res.type = alloc_type_pointer(ptr); + res.value = LLVMConstGEP2(lb_type(m, type), value.value, indices, gb_count_of(indices)); + return res; +} + + + LLVMValueRef llvm_zero(lbModule *m) { return LLVMConstInt(lb_type(m, t_int), 0, false); } diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 3d20b3d72..d424fa5b2 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -98,36 +98,8 @@ lbValue lb_type_info(lbModule *m, Type *type) { isize index = lb_type_info_index(m->info, type); GB_ASSERT(index >= 0); - LLVMTypeRef it = lb_type(m, t_int); - LLVMValueRef indices[2] = { - LLVMConstInt(it, 0, false), - LLVMConstInt(it, index, true), - }; - - lbValue value = {}; lbValue data = lb_global_type_info_data_ptr(m); - value.value = LLVMConstGEP2(lb_type(m, type_deref(data.type)), data.value, indices, gb_count_of(indices)); - value.type = t_type_info_ptr; - return value; -} - -lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { - GB_ASSERT(!build_context.disallow_rtti); - - i32 index = cast(i32)lb_type_info_index(m->info, type); - GB_ASSERT(index >= 0); - // gb_printf_err("%d %s\n", index, type_to_string(type)); - - LLVMValueRef indices[2] = { - LLVMConstInt(lb_type(m, t_int), 0, false), - LLVMConstInt(lb_type(m, t_int), index, false), - }; - - lbValue res = {}; - res.type = t_type_info_ptr; - lbValue data = lb_global_type_info_data_ptr(m); - res.value = LLVMConstGEP2(lb_type(m, type_deref(data.type)), data.value, indices, cast(unsigned)gb_count_of(indices)); - return res; + return lb_emit_array_epi(m, data, index); } LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) { @@ -267,7 +239,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da LLVMValueRef vals[4] = { lb_const_string(p->module, t->Named.type_name->token.string).value, - lb_get_type_info_ptr(m, t->Named.base).value, + lb_type_info(m, t->Named.base).value, pkg_name, loc.value }; @@ -426,7 +398,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da case Type_Pointer: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr); - lbValue gep = lb_get_type_info_ptr(m, t->Pointer.elem); + lbValue gep = lb_type_info(m, t->Pointer.elem); LLVMValueRef vals[1] = { gep.value, @@ -440,7 +412,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da } case Type_MultiPointer: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_multi_pointer_ptr); - lbValue gep = lb_get_type_info_ptr(m, t->MultiPointer.elem); + lbValue gep = lb_type_info(m, t->MultiPointer.elem); LLVMValueRef vals[1] = { gep.value, @@ -454,7 +426,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da } case Type_SoaPointer: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_soa_pointer_ptr); - lbValue gep = lb_get_type_info_ptr(m, t->SoaPointer.elem); + lbValue gep = lb_type_info(m, t->SoaPointer.elem); LLVMValueRef vals[1] = { gep.value, @@ -471,7 +443,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da i64 ez = type_size_of(t->Array.elem); LLVMValueRef vals[3] = { - lb_get_type_info_ptr(m, t->Array.elem).value, + lb_type_info(m, t->Array.elem).value, lb_const_int(m, t_int, ez).value, lb_const_int(m, t_int, t->Array.count).value, }; @@ -486,8 +458,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enumerated_array_ptr); LLVMValueRef vals[7] = { - lb_get_type_info_ptr(m, t->EnumeratedArray.elem).value, - lb_get_type_info_ptr(m, t->EnumeratedArray.index).value, + lb_type_info(m, t->EnumeratedArray.elem).value, + lb_type_info(m, t->EnumeratedArray.index).value, lb_const_int(m, t_int, type_size_of(t->EnumeratedArray.elem)).value, lb_const_int(m, t_int, t->EnumeratedArray.count).value, @@ -518,7 +490,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_dynamic_array_ptr); LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->DynamicArray.elem).value, + lb_type_info(m, t->DynamicArray.elem).value, lb_const_int(m, t_int, type_size_of(t->DynamicArray.elem)).value, }; @@ -532,7 +504,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_slice_ptr); LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->Slice.elem).value, + lb_type_info(m, t->Slice.elem).value, lb_const_int(m, t_int, type_size_of(t->Slice.elem)).value, }; @@ -548,10 +520,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da LLVMValueRef params = LLVMConstNull(lb_type(m, t_type_info_ptr)); LLVMValueRef results = LLVMConstNull(lb_type(m, t_type_info_ptr)); if (t->Proc.params != nullptr) { - params = lb_get_type_info_ptr(m, t->Proc.params).value; + params = lb_type_info(m, t->Proc.params).value; } if (t->Proc.results != nullptr) { - results = lb_get_type_info_ptr(m, t->Proc.results).value; + results = lb_type_info(m, t->Proc.results).value; } LLVMValueRef vals[4] = { @@ -670,7 +642,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da // NOTE(bill): Zeroth is nil so ignore it for (isize variant_index = 0; variant_index < variant_count; variant_index++) { Type *vt = t->Union.variants[variant_index]; - lbValue tip = lb_get_type_info_ptr(m, vt); + lbValue tip = lb_type_info(m, vt); lbValue index = lb_const_int(m, t_int, variant_index); lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); @@ -758,7 +730,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da for (isize source_index = 0; source_index < count; source_index++) { // TODO(bill): Order fields in source order not layout order Entity *f = t->Struct.fields[source_index]; - lbValue tip = lb_get_type_info_ptr(m, f->type); + lbValue tip = lb_type_info(m, f->type); i64 foffset = 0; if (!t->Struct.is_raw_union) { GB_ASSERT(t->Struct.offsets != nullptr); @@ -815,11 +787,11 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr); init_map_internal_types(t); - lbValue gst = lb_get_type_info_ptr(m, t->Map.generated_struct_type); + lbValue gst = lb_type_info(m, t->Map.generated_struct_type); LLVMValueRef vals[5] = { - lb_get_type_info_ptr(m, t->Map.key).value, - lb_get_type_info_ptr(m, t->Map.value).value, + lb_type_info(m, t->Map.key).value, + lb_type_info(m, t->Map.value).value, gst.value, lb_get_equal_proc_for_type(m, t->Map.key).value, lb_get_hasher_proc_for_type(m, t->Map.key).value @@ -840,13 +812,13 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da LLVMValueRef vals[4] = { - lb_get_type_info_ptr(m, t->BitSet.elem).value, + lb_type_info(m, t->BitSet.elem).value, LLVMConstNull(lb_type(m, t_type_info_ptr)), lb_const_int(m, t_i64, t->BitSet.lower).value, lb_const_int(m, t_i64, t->BitSet.upper).value, }; if (t->BitSet.underlying != nullptr) { - vals[1] =lb_get_type_info_ptr(m, t->BitSet.underlying).value; + vals[1] =lb_type_info(m, t->BitSet.underlying).value; } lbValue res = {}; @@ -862,7 +834,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da LLVMValueRef vals[3] = {}; - vals[0] = lb_get_type_info_ptr(m, t->SimdVector.elem).value; + vals[0] = lb_type_info(m, t->SimdVector.elem).value; vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value; vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value; @@ -877,8 +849,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_pointer_ptr); LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->RelativePointer.pointer_type).value, - lb_get_type_info_ptr(m, t->RelativePointer.base_integer).value, + lb_type_info(m, t->RelativePointer.pointer_type).value, + lb_type_info(m, t->RelativePointer.base_integer).value, }; lbValue res = {}; @@ -891,8 +863,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_slice_ptr); LLVMValueRef vals[2] = { - lb_get_type_info_ptr(m, t->RelativeSlice.slice_type).value, - lb_get_type_info_ptr(m, t->RelativeSlice.base_integer).value, + lb_type_info(m, t->RelativeSlice.slice_type).value, + lb_type_info(m, t->RelativeSlice.base_integer).value, }; lbValue res = {}; @@ -907,7 +879,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da i64 ez = type_size_of(t->Matrix.elem); LLVMValueRef vals[5] = { - lb_get_type_info_ptr(m, t->Matrix.elem).value, + lb_type_info(m, t->Matrix.elem).value, lb_const_int(m, t_int, ez).value, lb_const_int(m, t_int, matrix_type_stride_in_elems(t)).value, lb_const_int(m, t_int, t->Matrix.row_count).value, diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 3485c8436..ce7b43321 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1002,6 +1002,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { index = lb_convert_struct_index(p->module, t, index); if (lb_is_const(s)) { + // NOTE(bill): this cannot be replaced with lb_emit_epi lbModule *m = p->module; lbValue res = {}; LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)}; @@ -1252,27 +1253,13 @@ lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) { Type *ptr = base_array_type(st); lbValue res = {}; - res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, st), s.value, indices, 2, ""); - res.type = alloc_type_pointer(ptr); - return res; -} -// This emits a GEP at 0, index -static inline lbValue lb_emit_gep(lbProcedure *p, Type *type, LLVMValueRef value, isize index) -{ - LLVMValueRef indices[2] = { - LLVMConstInt(lb_type(p->module, t_int), 0, false), - LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)index, false), - }; - LLVMTypeRef llvm_type = lb_type(p->module, type); - lbValue res = {}; - Type *ptr = base_array_type(type); - res.type = alloc_type_pointer(ptr); - if (LLVMIsConstant(value)) { - res.value = LLVMConstGEP2(llvm_type, value, indices, gb_count_of(indices)); + if (LLVMIsConstant(s.value) && LLVMIsConstant(index.value)) { + res.value = LLVMConstGEP2(lb_type(p->module, st), s.value, indices, gb_count_of(indices)); } else { - res.value = LLVMBuildGEP2(p->builder, llvm_type, value, indices, gb_count_of(indices), ""); + res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, st), s.value, indices, gb_count_of(indices), ""); } + res.type = alloc_type_pointer(ptr); return res; } @@ -1282,7 +1269,15 @@ lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) { Type *st = base_type(type_deref(t)); GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); GB_ASSERT(0 <= index); - return lb_emit_gep(p, st, s.value, index); + return lb_emit_epi(p, s, index); +} +lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index) { + Type *t = s.type; + GB_ASSERT(is_type_pointer(t)); + Type *st = base_type(type_deref(t)); + GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); + GB_ASSERT(0 <= index); + return lb_emit_epi(m, s, index); } lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) { @@ -1306,16 +1301,16 @@ lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column) { Type *mt = base_type(type_deref(t)); if (column == 0) { GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt)); - return lb_emit_gep(p, mt, s.value, row); + return lb_emit_epi(p, s, row); } else if (row == 0 && is_type_array_like(mt)) { - return lb_emit_gep(p, mt, s.value, column); + return lb_emit_epi(p, s, column); } GB_ASSERT_MSG(is_type_matrix(mt), "%s", type_to_string(mt)); isize offset = matrix_indices_to_offset(mt, row, column); - return lb_emit_gep(p, mt, s.value, offset); + return lb_emit_epi(p, s, offset); } lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column) { -- cgit v1.2.3 From 28f440dd9e9e9674738b243d284a4394b22a5bc4 Mon Sep 17 00:00:00 2001 From: Joakim Hentula Date: Wed, 10 Aug 2022 13:58:33 +0100 Subject: Do not remove .rc extension from resource path to prevent expansion to full path assuming it's a directory if a folder with the same name exists in the same folder as the resource file --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 7fa04cc37..ef1b8dda1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1562,7 +1562,7 @@ bool parse_build_flags(Array args) { bad_flags = true; break; } - build_context.resource_filepath = substring(path, 0, string_extension_position(path)); + build_context.resource_filepath = path; build_context.has_resource = true; } else { gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path)); -- cgit v1.2.3 From 7aee762f3afe4ff40f7365082d45a32f52328e74 Mon Sep 17 00:00:00 2001 From: Jasper Yujin Geer Date: Wed, 10 Aug 2022 17:39:21 -0700 Subject: Throw error when untyped shift expressions have non-integral type hints --- src/check_expr.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b2f3567ba..4dab26572 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2505,11 +2505,20 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ x->expr->tav.is_lhs = true; } x->mode = Addressing_Value; - if (type_hint && is_type_integer(type_hint)) { - x->type = type_hint; + if (type_hint) { + if (is_type_integer(type_hint)) { + x->type = type_hint; + } else { + gbString expr_str = expr_to_string(node); + gbString to_type = type_to_string(type_hint); + error(node, "Cannot convert untyped expression '%s' to '%s'", expr_str, to_type); + gb_string_free(expr_str); + gb_string_free(to_type); + x->mode = Addressing_Invalid; + return; + } } // x->value = x_val; - return; } } @@ -2522,7 +2531,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ // TODO(bill): Should we support shifts for fixed arrays and #simd vectors? if (!is_type_integer(x->type)) { - gbString err_str = expr_to_string(y->expr); + gbString err_str = expr_to_string(x->expr); error(node, "Shift operand '%s' must be an integer", err_str); gb_string_free(err_str); x->mode = Addressing_Invalid; -- cgit v1.2.3 From 5b621d5be18523939ded57cba24b3b3d19b774bd Mon Sep 17 00:00:00 2001 From: Jasper Yujin Geer Date: Wed, 10 Aug 2022 18:07:49 -0700 Subject: More accurate error message --- src/check_expr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4dab26572..83bec20ae 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2509,10 +2509,10 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ if (is_type_integer(type_hint)) { x->type = type_hint; } else { - gbString expr_str = expr_to_string(node); + gbString x_str = expr_to_string(x->expr); gbString to_type = type_to_string(type_hint); - error(node, "Cannot convert untyped expression '%s' to '%s'", expr_str, to_type); - gb_string_free(expr_str); + error(node, "Conversion of shifted operand '%s' to '%s' is not allowed", x_str, to_type); + gb_string_free(x_str); gb_string_free(to_type); x->mode = Addressing_Invalid; return; -- cgit v1.2.3 From 57dd5ec4db2a8d4ea40a605a885e6a432d3ec568 Mon Sep 17 00:00:00 2001 From: Jasper Yujin Geer Date: Wed, 10 Aug 2022 18:25:29 -0700 Subject: Added back missing return statement --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 83bec20ae..f6c94466b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2515,10 +2515,10 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ gb_string_free(x_str); gb_string_free(to_type); x->mode = Addressing_Invalid; - return; } } // x->value = x_val; + return; } } -- cgit v1.2.3 From 0997df4fcf735830ee6a03867712ce89aa4255e1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 12:39:05 +0100 Subject: Move builtin directives to a separate procedure --- src/check_builtin.cpp | 907 +++++++++++++++++++++++++------------------------- 1 file changed, 455 insertions(+), 452 deletions(-) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 8f8f7f9e2..7a72c574f 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1075,6 +1075,459 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call } +bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { + ast_node(ce, CallExpr, call); + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + if (name == "location") { + if (ce->args.count > 1) { + error(ce->args[0], "'#location' expects either 0 or 1 arguments, got %td", ce->args.count); + } + if (ce->args.count > 0) { + Ast *arg = ce->args[0]; + Entity *e = nullptr; + Operand o = {}; + if (arg->kind == Ast_Ident) { + e = check_ident(c, &o, arg, nullptr, nullptr, true); + } else if (arg->kind == Ast_SelectorExpr) { + e = check_selector(c, &o, arg, nullptr); + } + if (e == nullptr) { + error(ce->args[0], "'#location' expected a valid entity name"); + } + } + + operand->type = t_source_code_location; + operand->mode = Addressing_Value; + } else if (name == "load") { + if (ce->args.count != 1) { + if (ce->args.count == 0) { + error(ce->close, "'#load' expects 1 argument, got 0"); + } else { + error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count); + } + + return false; + } + + Ast *arg = ce->args[0]; + Operand o = {}; + check_expr(c, &o, arg); + if (o.mode != Addressing_Constant) { + error(arg, "'#load' expected a constant string argument"); + return false; + } + + if (!is_type_string(o.type)) { + gbString str = type_to_string(o.type); + error(arg, "'#load' expected a constant string, got %s", str); + gb_string_free(str); + return false; + } + + gbAllocator a = heap_allocator(); + + GB_ASSERT(o.value.kind == ExactValue_String); + String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); + String original_string = o.value.value_string; + + + BlockingMutex *ignore_mutex = nullptr; + String path = {}; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + switch (file_err) { + default: + case gbFileError_Invalid: + error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str); + return false; + case gbFileError_NotExists: + error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str); + return false; + case gbFileError_Permission: + error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str); + return false; + case gbFileError_None: + // Okay + break; + } + + String result = {}; + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *data = cast(u8 *)gb_alloc(a, file_size+1); + gb_file_read_at(&f, data, file_size, 0); + data[file_size] = '\0'; + result.text = data; + result.len = file_size; + } + + operand->type = t_u8_slice; + operand->mode = Addressing_Constant; + operand->value = exact_value_string(result); + + } else if (name == "load_hash") { + if (ce->args.count != 2) { + if (ce->args.count == 0) { + error(ce->close, "'#load_hash' expects 2 argument, got 0"); + } else { + error(ce->args[0], "'#load_hash' expects 2 argument, got %td", ce->args.count); + } + return false; + } + + Ast *arg0 = ce->args[0]; + Ast *arg1 = ce->args[1]; + Operand o = {}; + check_expr(c, &o, arg0); + if (o.mode != Addressing_Constant) { + error(arg0, "'#load_hash' expected a constant string argument"); + return false; + } + + if (!is_type_string(o.type)) { + gbString str = type_to_string(o.type); + error(arg0, "'#load_hash' expected a constant string, got %s", str); + gb_string_free(str); + return false; + } + + Operand o_hash = {}; + check_expr(c, &o_hash, arg1); + if (o_hash.mode != Addressing_Constant) { + error(arg1, "'#load_hash' expected a constant string argument"); + return false; + } + + if (!is_type_string(o_hash.type)) { + gbString str = type_to_string(o.type); + error(arg1, "'#load_hash' expected a constant string, got %s", str); + gb_string_free(str); + return false; + } + + + gbAllocator a = heap_allocator(); + + GB_ASSERT(o.value.kind == ExactValue_String); + GB_ASSERT(o_hash.value.kind == ExactValue_String); + + String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); + String original_string = o.value.value_string; + String hash_kind = o_hash.value.value_string; + + String supported_hashes[] = { + str_lit("adler32"), + str_lit("crc32"), + str_lit("crc64"), + str_lit("fnv32"), + str_lit("fnv64"), + str_lit("fnv32a"), + str_lit("fnv64a"), + str_lit("murmur32"), + str_lit("murmur64"), + }; + + bool hash_found = false; + for (isize i = 0; i < gb_count_of(supported_hashes); i++) { + if (supported_hashes[i] == hash_kind) { + hash_found = true; + break; + } + } + if (!hash_found) { + ERROR_BLOCK(); + error(ce->proc, "Invalid hash kind passed to `#load_hash`, got: %.*s", LIT(hash_kind)); + error_line("\tAvailable hash kinds:\n"); + for (isize i = 0; i < gb_count_of(supported_hashes); i++) { + error_line("\t%.*s\n", LIT(supported_hashes[i])); + } + return false; + } + + + BlockingMutex *ignore_mutex = nullptr; + String path = {}; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + switch (file_err) { + default: + case gbFileError_Invalid: + error(ce->proc, "Failed to `#load_hash` file: %s; invalid file or cannot be found", c_str); + return false; + case gbFileError_NotExists: + error(ce->proc, "Failed to `#load_hash` file: %s; file cannot be found", c_str); + return false; + case gbFileError_Permission: + error(ce->proc, "Failed to `#load_hash` file: %s; file permissions problem", c_str); + return false; + case gbFileError_None: + // Okay + break; + } + + // TODO(bill): make these procedures fast :P + + u64 hash_value = 0; + String result = {}; + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *data = cast(u8 *)gb_alloc(a, file_size); + gb_file_read_at(&f, data, file_size, 0); + if (hash_kind == "adler32") { + hash_value = gb_adler32(data, file_size); + } else if (hash_kind == "crc32") { + hash_value = gb_crc32(data, file_size); + } else if (hash_kind == "crc64") { + hash_value = gb_crc64(data, file_size); + } else if (hash_kind == "fnv32") { + hash_value = gb_fnv32(data, file_size); + } else if (hash_kind == "fnv64") { + hash_value = gb_fnv64(data, file_size); + } else if (hash_kind == "fnv32a") { + hash_value = fnv32a(data, file_size); + } else if (hash_kind == "fnv64a") { + hash_value = fnv64a(data, file_size); + } else if (hash_kind == "murmur32") { + hash_value = gb_murmur32(data, file_size); + } else if (hash_kind == "murmur64") { + hash_value = gb_murmur64(data, file_size); + } else { + compiler_error("unhandled hash kind: %.*s", LIT(hash_kind)); + } + gb_free(a, data); + } + + operand->type = t_untyped_integer; + operand->mode = Addressing_Constant; + operand->value = exact_value_u64(hash_value); + + } else if (name == "load_or") { + if (ce->args.count != 2) { + if (ce->args.count == 0) { + error(ce->close, "'#load_or' expects 2 arguments, got 0"); + } else { + error(ce->args[0], "'#load_or' expects 2 arguments, got %td", ce->args.count); + } + return false; + } + + Ast *arg = ce->args[0]; + Operand o = {}; + check_expr(c, &o, arg); + if (o.mode != Addressing_Constant) { + error(arg, "'#load_or' expected a constant string argument"); + return false; + } + + if (!is_type_string(o.type)) { + gbString str = type_to_string(o.type); + error(arg, "'#load_or' expected a constant string, got %s", str); + gb_string_free(str); + return false; + } + + Ast *default_arg = ce->args[1]; + Operand default_op = {}; + check_expr_with_type_hint(c, &default_op, default_arg, t_u8_slice); + if (default_op.mode != Addressing_Constant) { + error(arg, "'#load_or' expected a constant '[]byte' argument"); + return false; + } + + if (!are_types_identical(base_type(default_op.type), t_u8_slice)) { + gbString str = type_to_string(default_op.type); + error(arg, "'#load_or' expected a constant '[]byte', got %s", str); + gb_string_free(str); + return false; + } + + gbAllocator a = heap_allocator(); + + GB_ASSERT(o.value.kind == ExactValue_String); + String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); + String original_string = o.value.value_string; + + + BlockingMutex *ignore_mutex = nullptr; + String path = {}; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + operand->type = t_u8_slice; + operand->mode = Addressing_Constant; + if (file_err == gbFileError_None) { + String result = {}; + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *data = cast(u8 *)gb_alloc(a, file_size+1); + gb_file_read_at(&f, data, file_size, 0); + data[file_size] = '\0'; + result.text = data; + result.len = file_size; + } + + operand->value = exact_value_string(result); + } else { + operand->value = default_op.value; + } + + } else if (name == "assert") { + if (ce->args.count != 1 && ce->args.count != 2) { + error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count); + return false; + } + if (!is_type_boolean(operand->type) || operand->mode != Addressing_Constant) { + gbString str = expr_to_string(ce->args[0]); + error(call, "'%s' is not a constant boolean", str); + gb_string_free(str); + return false; + } + if (ce->args.count == 2) { + Ast *arg = unparen_expr(ce->args[1]); + if (arg == nullptr || arg->kind != Ast_BasicLit || arg->BasicLit.token.kind != Token_String) { + gbString str = expr_to_string(arg); + error(call, "'%s' is not a constant string", str); + gb_string_free(str); + return false; + } + } + + if (!operand->value.value_bool) { + gbString arg1 = expr_to_string(ce->args[0]); + gbString arg2 = {}; + + if (ce->args.count == 1) { + error(call, "Compile time assertion: %s", arg1); + } else { + arg2 = expr_to_string(ce->args[1]); + error(call, "Compile time assertion: %s (%s)", arg1, arg2); + } + + if (c->proc_name != "") { + gbString str = type_to_string(c->curr_proc_sig); + error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); + gb_string_free(str); + } + + gb_string_free(arg1); + if (ce->args.count == 2) { + gb_string_free(arg2); + } + } + + operand->type = t_untyped_bool; + operand->mode = Addressing_Constant; + } else if (name == "panic") { + if (ce->args.count != 1) { + error(call, "'#panic' expects 1 argument, got %td", ce->args.count); + return false; + } + if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) { + gbString str = expr_to_string(ce->args[0]); + error(call, "'%s' is not a constant string", str); + gb_string_free(str); + return false; + } + error(call, "Compile time panic: %.*s", LIT(operand->value.value_string)); + if (c->proc_name != "") { + gbString str = type_to_string(c->curr_proc_sig); + error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); + gb_string_free(str); + } + operand->type = t_invalid; + operand->mode = Addressing_NoValue; + } else if (name == "defined") { + if (ce->args.count != 1) { + error(call, "'#defined' expects 1 argument, got %td", ce->args.count); + return false; + } + Ast *arg = unparen_expr(ce->args[0]); + if (arg == nullptr || (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr)) { + error(call, "'#defined' expects an identifier or selector expression, got %.*s", LIT(ast_strings[arg->kind])); + return false; + } + + if (c->curr_proc_decl == nullptr) { + error(call, "'#defined' is only allowed within a procedure, prefer the replacement '#config(NAME, default_value)'"); + return false; + } + + bool is_defined = check_identifier_exists(c->scope, arg); + gb_unused(is_defined); + operand->type = t_untyped_bool; + operand->mode = Addressing_Constant; + operand->value = exact_value_bool(false); + + } else if (name == "config") { + if (ce->args.count != 2) { + error(call, "'#config' expects 2 argument, got %td", ce->args.count); + return false; + } + Ast *arg = unparen_expr(ce->args[0]); + if (arg == nullptr || arg->kind != Ast_Ident) { + error(call, "'#config' expects an identifier, got %.*s", LIT(ast_strings[arg->kind])); + return false; + } + + Ast *def_arg = unparen_expr(ce->args[1]); + + Operand def = {}; + check_expr(c, &def, def_arg); + if (def.mode != Addressing_Constant) { + error(def_arg, "'#config' default value must be a constant"); + return false; + } + + String name = arg->Ident.token.string; + + + operand->type = def.type; + operand->mode = def.mode; + operand->value = def.value; + + Entity *found = scope_lookup_current(config_pkg->scope, name); + if (found != nullptr) { + if (found->kind != Entity_Constant) { + error(arg, "'#config' entity '%.*s' found but expected a constant", LIT(name)); + } else { + operand->type = found->type; + operand->mode = Addressing_Constant; + operand->value = found->Constant.value; + } + } + } else { + error(call, "Unknown directive call: #%.*s", LIT(name)); + } + return true; +} + bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { ast_node(ce, CallExpr, call); if (ce->inlining != ProcInlining_none) { @@ -1186,458 +1639,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 mpmc_enqueue(&c->info->intrinsics_entry_point_usage, call); break; - case BuiltinProc_DIRECTIVE: { - ast_node(bd, BasicDirective, ce->proc); - String name = bd->name.string; - if (name == "location") { - if (ce->args.count > 1) { - error(ce->args[0], "'#location' expects either 0 or 1 arguments, got %td", ce->args.count); - } - if (ce->args.count > 0) { - Ast *arg = ce->args[0]; - Entity *e = nullptr; - Operand o = {}; - if (arg->kind == Ast_Ident) { - e = check_ident(c, &o, arg, nullptr, nullptr, true); - } else if (arg->kind == Ast_SelectorExpr) { - e = check_selector(c, &o, arg, nullptr); - } - if (e == nullptr) { - error(ce->args[0], "'#location' expected a valid entity name"); - } - } - - operand->type = t_source_code_location; - operand->mode = Addressing_Value; - } else if (name == "load") { - if (ce->args.count != 1) { - if (ce->args.count == 0) { - error(ce->close, "'#load' expects 1 argument, got 0"); - } else { - error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count); - } - - return false; - } - - Ast *arg = ce->args[0]; - Operand o = {}; - check_expr(c, &o, arg); - if (o.mode != Addressing_Constant) { - error(arg, "'#load' expected a constant string argument"); - return false; - } - - if (!is_type_string(o.type)) { - gbString str = type_to_string(o.type); - error(arg, "'#load' expected a constant string, got %s", str); - gb_string_free(str); - return false; - } - - gbAllocator a = heap_allocator(); - - GB_ASSERT(o.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); - String original_string = o.value.value_string; - - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - default: - case gbFileError_Invalid: - error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str); - return false; - case gbFileError_NotExists: - error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str); - return false; - case gbFileError_Permission: - error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str); - return false; - case gbFileError_None: - // Okay - break; - } - - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size+1); - gb_file_read_at(&f, data, file_size, 0); - data[file_size] = '\0'; - result.text = data; - result.len = file_size; - } - - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; - operand->value = exact_value_string(result); - - } else if (name == "load_hash") { - if (ce->args.count != 2) { - if (ce->args.count == 0) { - error(ce->close, "'#load_hash' expects 2 argument, got 0"); - } else { - error(ce->args[0], "'#load_hash' expects 2 argument, got %td", ce->args.count); - } - return false; - } - - Ast *arg0 = ce->args[0]; - Ast *arg1 = ce->args[1]; - Operand o = {}; - check_expr(c, &o, arg0); - if (o.mode != Addressing_Constant) { - error(arg0, "'#load_hash' expected a constant string argument"); - return false; - } - - if (!is_type_string(o.type)) { - gbString str = type_to_string(o.type); - error(arg0, "'#load_hash' expected a constant string, got %s", str); - gb_string_free(str); - return false; - } - - Operand o_hash = {}; - check_expr(c, &o_hash, arg1); - if (o_hash.mode != Addressing_Constant) { - error(arg1, "'#load_hash' expected a constant string argument"); - return false; - } - - if (!is_type_string(o_hash.type)) { - gbString str = type_to_string(o.type); - error(arg1, "'#load_hash' expected a constant string, got %s", str); - gb_string_free(str); - return false; - } - - - gbAllocator a = heap_allocator(); - - GB_ASSERT(o.value.kind == ExactValue_String); - GB_ASSERT(o_hash.value.kind == ExactValue_String); - - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); - String original_string = o.value.value_string; - String hash_kind = o_hash.value.value_string; - - String supported_hashes[] = { - str_lit("adler32"), - str_lit("crc32"), - str_lit("crc64"), - str_lit("fnv32"), - str_lit("fnv64"), - str_lit("fnv32a"), - str_lit("fnv64a"), - str_lit("murmur32"), - str_lit("murmur64"), - }; - - bool hash_found = false; - for (isize i = 0; i < gb_count_of(supported_hashes); i++) { - if (supported_hashes[i] == hash_kind) { - hash_found = true; - break; - } - } - if (!hash_found) { - ERROR_BLOCK(); - error(ce->proc, "Invalid hash kind passed to `#load_hash`, got: %.*s", LIT(hash_kind)); - error_line("\tAvailable hash kinds:\n"); - for (isize i = 0; i < gb_count_of(supported_hashes); i++) { - error_line("\t%.*s\n", LIT(supported_hashes[i])); - } - return false; - } - - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - default: - case gbFileError_Invalid: - error(ce->proc, "Failed to `#load_hash` file: %s; invalid file or cannot be found", c_str); - return false; - case gbFileError_NotExists: - error(ce->proc, "Failed to `#load_hash` file: %s; file cannot be found", c_str); - return false; - case gbFileError_Permission: - error(ce->proc, "Failed to `#load_hash` file: %s; file permissions problem", c_str); - return false; - case gbFileError_None: - // Okay - break; - } - - // TODO(bill): make these procedures fast :P - - u64 hash_value = 0; - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size); - gb_file_read_at(&f, data, file_size, 0); - if (hash_kind == "adler32") { - hash_value = gb_adler32(data, file_size); - } else if (hash_kind == "crc32") { - hash_value = gb_crc32(data, file_size); - } else if (hash_kind == "crc64") { - hash_value = gb_crc64(data, file_size); - } else if (hash_kind == "fnv32") { - hash_value = gb_fnv32(data, file_size); - } else if (hash_kind == "fnv64") { - hash_value = gb_fnv64(data, file_size); - } else if (hash_kind == "fnv32a") { - hash_value = fnv32a(data, file_size); - } else if (hash_kind == "fnv64a") { - hash_value = fnv64a(data, file_size); - } else if (hash_kind == "murmur32") { - hash_value = gb_murmur32(data, file_size); - } else if (hash_kind == "murmur64") { - hash_value = gb_murmur64(data, file_size); - } else { - compiler_error("unhandled hash kind: %.*s", LIT(hash_kind)); - } - gb_free(a, data); - } - - operand->type = t_untyped_integer; - operand->mode = Addressing_Constant; - operand->value = exact_value_u64(hash_value); - - } else if (name == "load_or") { - if (ce->args.count != 2) { - if (ce->args.count == 0) { - error(ce->close, "'#load_or' expects 2 arguments, got 0"); - } else { - error(ce->args[0], "'#load_or' expects 2 arguments, got %td", ce->args.count); - } - return false; - } - - Ast *arg = ce->args[0]; - Operand o = {}; - check_expr(c, &o, arg); - if (o.mode != Addressing_Constant) { - error(arg, "'#load_or' expected a constant string argument"); - return false; - } - - if (!is_type_string(o.type)) { - gbString str = type_to_string(o.type); - error(arg, "'#load_or' expected a constant string, got %s", str); - gb_string_free(str); - return false; - } - - Ast *default_arg = ce->args[1]; - Operand default_op = {}; - check_expr_with_type_hint(c, &default_op, default_arg, t_u8_slice); - if (default_op.mode != Addressing_Constant) { - error(arg, "'#load_or' expected a constant '[]byte' argument"); - return false; - } - - if (!are_types_identical(base_type(default_op.type), t_u8_slice)) { - gbString str = type_to_string(default_op.type); - error(arg, "'#load_or' expected a constant '[]byte', got %s", str); - gb_string_free(str); - return false; - } - - gbAllocator a = heap_allocator(); - - GB_ASSERT(o.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); - String original_string = o.value.value_string; - - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; - if (file_err == gbFileError_None) { - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size+1); - gb_file_read_at(&f, data, file_size, 0); - data[file_size] = '\0'; - result.text = data; - result.len = file_size; - } - - operand->value = exact_value_string(result); - } else { - operand->value = default_op.value; - } - - } else if (name == "assert") { - if (ce->args.count != 1 && ce->args.count != 2) { - error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count); - return false; - } - if (!is_type_boolean(operand->type) || operand->mode != Addressing_Constant) { - gbString str = expr_to_string(ce->args[0]); - error(call, "'%s' is not a constant boolean", str); - gb_string_free(str); - return false; - } - if (ce->args.count == 2) { - Ast *arg = unparen_expr(ce->args[1]); - if (arg == nullptr || arg->kind != Ast_BasicLit || arg->BasicLit.token.kind != Token_String) { - gbString str = expr_to_string(arg); - error(call, "'%s' is not a constant string", str); - gb_string_free(str); - return false; - } - } - - if (!operand->value.value_bool) { - gbString arg1 = expr_to_string(ce->args[0]); - gbString arg2 = {}; - - if (ce->args.count == 1) { - error(call, "Compile time assertion: %s", arg1); - } else { - arg2 = expr_to_string(ce->args[1]); - error(call, "Compile time assertion: %s (%s)", arg1, arg2); - } - - if (c->proc_name != "") { - gbString str = type_to_string(c->curr_proc_sig); - error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); - gb_string_free(str); - } - - gb_string_free(arg1); - if (ce->args.count == 2) { - gb_string_free(arg2); - } - } - - operand->type = t_untyped_bool; - operand->mode = Addressing_Constant; - } else if (name == "panic") { - if (ce->args.count != 1) { - error(call, "'#panic' expects 1 argument, got %td", ce->args.count); - return false; - } - if (!is_type_string(operand->type) && operand->mode != Addressing_Constant) { - gbString str = expr_to_string(ce->args[0]); - error(call, "'%s' is not a constant string", str); - gb_string_free(str); - return false; - } - error(call, "Compile time panic: %.*s", LIT(operand->value.value_string)); - if (c->proc_name != "") { - gbString str = type_to_string(c->curr_proc_sig); - error_line("\tCalled within '%.*s' :: %s\n", LIT(c->proc_name), str); - gb_string_free(str); - } - operand->type = t_invalid; - operand->mode = Addressing_NoValue; - } else if (name == "defined") { - if (ce->args.count != 1) { - error(call, "'#defined' expects 1 argument, got %td", ce->args.count); - return false; - } - Ast *arg = unparen_expr(ce->args[0]); - if (arg == nullptr || (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr)) { - error(call, "'#defined' expects an identifier or selector expression, got %.*s", LIT(ast_strings[arg->kind])); - return false; - } - - if (c->curr_proc_decl == nullptr) { - error(call, "'#defined' is only allowed within a procedure, prefer the replacement '#config(NAME, default_value)'"); - return false; - } - - bool is_defined = check_identifier_exists(c->scope, arg); - gb_unused(is_defined); - operand->type = t_untyped_bool; - operand->mode = Addressing_Constant; - operand->value = exact_value_bool(false); - - } else if (name == "config") { - if (ce->args.count != 2) { - error(call, "'#config' expects 2 argument, got %td", ce->args.count); - return false; - } - Ast *arg = unparen_expr(ce->args[0]); - if (arg == nullptr || arg->kind != Ast_Ident) { - error(call, "'#config' expects an identifier, got %.*s", LIT(ast_strings[arg->kind])); - return false; - } - - Ast *def_arg = unparen_expr(ce->args[1]); - - Operand def = {}; - check_expr(c, &def, def_arg); - if (def.mode != Addressing_Constant) { - error(def_arg, "'#config' default value must be a constant"); - return false; - } - - String name = arg->Ident.token.string; - - - operand->type = def.type; - operand->mode = def.mode; - operand->value = def.value; - - Entity *found = scope_lookup_current(config_pkg->scope, name); - if (found != nullptr) { - if (found->kind != Entity_Constant) { - error(arg, "'#config' entity '%.*s' found but expected a constant", LIT(name)); - } else { - operand->type = found->type; - operand->mode = Addressing_Constant; - operand->value = found->Constant.value; - } - } - } else { - error(call, "Unknown directive call: #%.*s", LIT(name)); - } - - break; - } + case BuiltinProc_DIRECTIVE: + return check_builtin_procedure_directive(c, operand, call, id, type_hint); case BuiltinProc_len: check_expr_or_type(c, operand, ce->args[0]); -- cgit v1.2.3 From 38102f14c19f83ef1e0c13a824448bab4e80877e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 13:01:54 +0100 Subject: Add `#load(path) or_else default` in favour of `#load_or(path, default)` --- src/check_builtin.cpp | 175 ++++++++++++++++++++++++------------------- src/check_expr.cpp | 70 ++++++++++++++++- src/llvm_backend_utility.cpp | 4 + src/parser.hpp | 3 +- 4 files changed, 171 insertions(+), 81 deletions(-) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 7a72c574f..4a0863f9d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1074,8 +1074,100 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call return false; } +LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) { + ast_node(ce, CallExpr, call); + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + GB_ASSERT(name == "load"); + + if (ce->args.count != 1) { + if (ce->args.count == 0) { + error(ce->close, "'#load' expects 1 argument, got 0"); + } else { + error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count); + } + + return LoadDirective_Error; + } + + Ast *arg = ce->args[0]; + Operand o = {}; + check_expr(c, &o, arg); + if (o.mode != Addressing_Constant) { + error(arg, "'#load' expected a constant string argument"); + return LoadDirective_Error; + } + + if (!is_type_string(o.type)) { + gbString str = type_to_string(o.type); + error(arg, "'#load' expected a constant string, got %s", str); + gb_string_free(str); + return LoadDirective_Error; + } + + gbAllocator a = heap_allocator(); + + GB_ASSERT(o.value.kind == ExactValue_String); + String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); + String original_string = o.value.value_string; + + + BlockingMutex *ignore_mutex = nullptr; + String path = {}; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + switch (file_err) { + default: + case gbFileError_Invalid: + if (err_on_not_found) { + error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return LoadDirective_NotFound; + case gbFileError_NotExists: + if (err_on_not_found) { + error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return LoadDirective_NotFound; + case gbFileError_Permission: + if (err_on_not_found) { + error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return LoadDirective_NotFound; + case gbFileError_None: + // Okay + break; + } -bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) { + String result = {}; + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *data = cast(u8 *)gb_alloc(a, file_size+1); + gb_file_read_at(&f, data, file_size, 0); + data[file_size] = '\0'; + result.text = data; + result.len = file_size; + } + + operand->type = t_u8_slice; + operand->mode = Addressing_Constant; + operand->value = exact_value_string(result); + return LoadDirective_Success; +} + + +bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); String name = bd->name.string; @@ -1100,81 +1192,7 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast operand->type = t_source_code_location; operand->mode = Addressing_Value; } else if (name == "load") { - if (ce->args.count != 1) { - if (ce->args.count == 0) { - error(ce->close, "'#load' expects 1 argument, got 0"); - } else { - error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count); - } - - return false; - } - - Ast *arg = ce->args[0]; - Operand o = {}; - check_expr(c, &o, arg); - if (o.mode != Addressing_Constant) { - error(arg, "'#load' expected a constant string argument"); - return false; - } - - if (!is_type_string(o.type)) { - gbString str = type_to_string(o.type); - error(arg, "'#load' expected a constant string, got %s", str); - gb_string_free(str); - return false; - } - - gbAllocator a = heap_allocator(); - - GB_ASSERT(o.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); - String original_string = o.value.value_string; - - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - default: - case gbFileError_Invalid: - error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str); - return false; - case gbFileError_NotExists: - error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str); - return false; - case gbFileError_Permission: - error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str); - return false; - case gbFileError_None: - // Okay - break; - } - - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size+1); - gb_file_read_at(&f, data, file_size, 0); - data[file_size] = '\0'; - result.text = data; - result.len = file_size; - } - - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; - operand->value = exact_value_string(result); - + return check_load_directive(c, operand, call, type_hint, true) == LoadDirective_Success; } else if (name == "load_hash") { if (ce->args.count != 2) { if (ce->args.count == 0) { @@ -1263,7 +1281,6 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast char *c_str = alloc_cstring(a, path); defer (gb_free(a, c_str)); - gbFile f = {}; gbFileError file_err = gb_file_open(&f, c_str); defer (gb_file_close(&f)); @@ -1321,6 +1338,8 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast operand->value = exact_value_u64(hash_value); } else if (name == "load_or") { + warning(call, "'#load_or' is deprecated in favour of '#load(path) or_else default'"); + if (ce->args.count != 2) { if (ce->args.count == 0) { error(ce->close, "'#load_or' expects 2 arguments, got 0"); @@ -1640,7 +1659,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 break; case BuiltinProc_DIRECTIVE: - return check_builtin_procedure_directive(c, operand, call, id, type_hint); + return check_builtin_procedure_directive(c, operand, call, type_hint); case BuiltinProc_len: check_expr_or_type(c, operand, ce->args[0]); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f6c94466b..ae459574c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -121,6 +121,28 @@ void check_or_return_split_types(CheckerContext *c, Operand *x, String const &na bool is_diverging_expr(Ast *expr); + +enum LoadDirectiveResult { + LoadDirective_Success = 0, + LoadDirective_Error = 1, + LoadDirective_NotFound = 2, +}; + +bool is_load_directive_call(Ast *call) { + call = unparen_expr(call); + if (call->kind != Ast_CallExpr) { + return false; + } + ast_node(ce, CallExpr, call); + if (ce->proc->kind != Ast_BasicDirective) { + return false; + } + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + return name == "load"; +} +LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found); + void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { auto results = did_you_mean_results(d); if (results.count != 0) { @@ -7407,9 +7429,54 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type String name = oe->token.string; Ast *arg = oe->x; Ast *default_value = oe->y; - Operand x = {}; Operand y = {}; + + // NOTE(bill, 2022-08-11): edge case to handle #load(path) or_else default + if (is_load_directive_call(arg)) { + LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false); + if (res == LoadDirective_Success) { + *o = x; + return Expr_Expr; + } + + bool y_is_diverging = false; + check_expr_base(c, &y, default_value, x.type); + switch (y.mode) { + case Addressing_NoValue: + if (is_diverging_expr(y.expr)) { + // Allow + y.mode = Addressing_Value; + y_is_diverging = true; + } else { + error_operand_no_value(&y); + y.mode = Addressing_Invalid; + } + break; + case Addressing_Type: + error_operand_not_expression(&y); + y.mode = Addressing_Invalid; + break; + } + + if (y.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + o->expr = node; + return Expr_Expr; + } + + if (!y_is_diverging) { + check_assignment(c, &y, x.type, name); + } + + o->mode = y.mode; + o->type = y.type; + o->expr = node; + + return Expr_Expr; + } + check_multi_expr_with_type_hint(c, &x, arg, type_hint); if (x.mode == Addressing_Invalid) { o->mode = Addressing_Value; @@ -7417,7 +7484,6 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type o->expr = node; return Expr_Expr; } - bool y_is_diverging = false; check_expr_base(c, &y, default_value, x.type); switch (y.mode) { diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index ce7b43321..09c45cb7a 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -351,6 +351,10 @@ lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) { lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue const &tv) { + if (arg->state_flags & StateFlag_DirectiveWasFalse) { + return lb_build_expr(p, else_expr); + } + lbValue lhs = {}; lbValue rhs = {}; lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs); diff --git a/src/parser.hpp b/src/parser.hpp index bfdae58a5..7433744e6 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -282,7 +282,8 @@ enum StateFlag : u8 { StateFlag_type_assert = 1<<2, StateFlag_no_type_assert = 1<<3, - StateFlag_SelectorCallExpr = 1<<6, + StateFlag_SelectorCallExpr = 1<<5, + StateFlag_DirectiveWasFalse = 1<<6, StateFlag_BeenHandled = 1<<7, }; -- cgit v1.2.3 From a054c2934eb0caa027a1663cca839cb422621558 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 13:32:45 +0100 Subject: Cache #load data and hashes --- src/check_builtin.cpp | 254 ++++++++++++++++++++++++++------------------------ src/checker.cpp | 4 + src/checker.hpp | 9 ++ 3 files changed, 147 insertions(+), 120 deletions(-) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 4a0863f9d..70b5a0a13 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1074,6 +1074,95 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call return false; } +bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_) { + ast_node(ce, CallExpr, call); + ast_node(bd, BasicDirective, ce->proc); + String builtin_name = bd->name.string; + + String base_dir = dir_from_path(get_file_path_string(call->file_id)); + + BlockingMutex *ignore_mutex = nullptr; + String path = {}; + bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); + gb_unused(ok); + + + MUTEX_GUARD(&c->info->load_file_mutex); + + gbFileError file_error = gbFileError_None; + String data = {}; + + LoadFileCache **cache_ptr = string_map_get(&c->info->load_file_cache, path); + LoadFileCache *cache = cache_ptr ? *cache_ptr : nullptr; + if (cache) { + file_error = cache->file_error; + data = cache->data; + } + defer ({ + if (cache == nullptr) { + LoadFileCache *new_cache = gb_alloc_item(permanent_allocator(), LoadFileCache); + new_cache->path = path; + new_cache->data = data; + new_cache->file_error = file_error; + string_map_init(&new_cache->hashes, heap_allocator(), 32); + string_map_set(&c->info->load_file_cache, path, new_cache); + if (cache_) *cache_ = new_cache; + } else { + cache->data = data; + cache->file_error = file_error; + if (cache_) *cache_ = cache; + } + }); + + char *c_str = alloc_cstring(heap_allocator(), path); + defer (gb_free(heap_allocator(), c_str)); + + gbFile f = {}; + if (cache == nullptr) { + file_error = gb_file_open(&f, c_str); + } + defer (gb_file_close(&f)); + + switch (file_error) { + default: + case gbFileError_Invalid: + if (err_on_not_found) { + error(ce->proc, "Failed to `#%.*s` file: %s; invalid file or cannot be found", LIT(builtin_name), c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return false; + case gbFileError_NotExists: + if (err_on_not_found) { + error(ce->proc, "Failed to `#%.*s` file: %s; file cannot be found", LIT(builtin_name), c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return false; + case gbFileError_Permission: + if (err_on_not_found) { + error(ce->proc, "Failed to `#%.*s` file: %s; file permissions problem", LIT(builtin_name), c_str); + } + call->state_flags |= StateFlag_DirectiveWasFalse; + return false; + case gbFileError_None: + // Okay + break; + } + + if (cache == nullptr) { + isize file_size = cast(isize)gb_file_size(&f); + if (file_size > 0) { + u8 *ptr = cast(u8 *)gb_alloc(permanent_allocator(), file_size+1); + gb_file_read_at(&f, ptr, file_size, 0); + ptr[file_size] = '\0'; + data.text = ptr; + data.len = file_size; + } + } + + return true; +} + + LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); @@ -1105,65 +1194,17 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As return LoadDirective_Error; } - gbAllocator a = heap_allocator(); - GB_ASSERT(o.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); - String original_string = o.value.value_string; - - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - default: - case gbFileError_Invalid: - if (err_on_not_found) { - error(ce->proc, "Failed to `#load` file: %s; invalid file or cannot be found", c_str); - } - call->state_flags |= StateFlag_DirectiveWasFalse; - return LoadDirective_NotFound; - case gbFileError_NotExists: - if (err_on_not_found) { - error(ce->proc, "Failed to `#load` file: %s; file cannot be found", c_str); - } - call->state_flags |= StateFlag_DirectiveWasFalse; - return LoadDirective_NotFound; - case gbFileError_Permission: - if (err_on_not_found) { - error(ce->proc, "Failed to `#load` file: %s; file permissions problem", c_str); - } - call->state_flags |= StateFlag_DirectiveWasFalse; - return LoadDirective_NotFound; - case gbFileError_None: - // Okay - break; - } - - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size+1); - gb_file_read_at(&f, data, file_size, 0); - data[file_size] = '\0'; - result.text = data; - result.len = file_size; + LoadFileCache *cache = nullptr; + if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache)) { + operand->type = t_u8_slice; + operand->mode = Addressing_Constant; + operand->value = exact_value_string(cache->data); + return LoadDirective_Success; } + return LoadDirective_NotFound; - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; - operand->value = exact_value_string(result); - return LoadDirective_Success; } @@ -1232,14 +1273,11 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast gb_string_free(str); return false; } - - gbAllocator a = heap_allocator(); GB_ASSERT(o.value.kind == ExactValue_String); GB_ASSERT(o_hash.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); String original_string = o.value.value_string; String hash_kind = o_hash.value.value_string; @@ -1272,71 +1310,47 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast return false; } - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - - switch (file_err) { - default: - case gbFileError_Invalid: - error(ce->proc, "Failed to `#load_hash` file: %s; invalid file or cannot be found", c_str); - return false; - case gbFileError_NotExists: - error(ce->proc, "Failed to `#load_hash` file: %s; file cannot be found", c_str); - return false; - case gbFileError_Permission: - error(ce->proc, "Failed to `#load_hash` file: %s; file permissions problem", c_str); - return false; - case gbFileError_None: - // Okay - break; - } - - // TODO(bill): make these procedures fast :P - - u64 hash_value = 0; - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size); - gb_file_read_at(&f, data, file_size, 0); - if (hash_kind == "adler32") { - hash_value = gb_adler32(data, file_size); - } else if (hash_kind == "crc32") { - hash_value = gb_crc32(data, file_size); - } else if (hash_kind == "crc64") { - hash_value = gb_crc64(data, file_size); - } else if (hash_kind == "fnv32") { - hash_value = gb_fnv32(data, file_size); - } else if (hash_kind == "fnv64") { - hash_value = gb_fnv64(data, file_size); - } else if (hash_kind == "fnv32a") { - hash_value = fnv32a(data, file_size); - } else if (hash_kind == "fnv64a") { - hash_value = fnv64a(data, file_size); - } else if (hash_kind == "murmur32") { - hash_value = gb_murmur32(data, file_size); - } else if (hash_kind == "murmur64") { - hash_value = gb_murmur64(data, file_size); + LoadFileCache *cache = nullptr; + if (cache_load_file_directive(c, call, original_string, true, &cache)) { + MUTEX_GUARD(&c->info->load_file_mutex); + // TODO(bill): make these procedures fast :P + u64 hash_value = 0; + u64 *hash_value_ptr = string_map_get(&cache->hashes, hash_kind); + if (hash_value_ptr) { + hash_value = *hash_value_ptr; } else { - compiler_error("unhandled hash kind: %.*s", LIT(hash_kind)); + u8 *data = cache->data.text; + isize file_size = cache->data.len; + if (hash_kind == "adler32") { + hash_value = gb_adler32(data, file_size); + } else if (hash_kind == "crc32") { + hash_value = gb_crc32(data, file_size); + } else if (hash_kind == "crc64") { + hash_value = gb_crc64(data, file_size); + } else if (hash_kind == "fnv32") { + hash_value = gb_fnv32(data, file_size); + } else if (hash_kind == "fnv64") { + hash_value = gb_fnv64(data, file_size); + } else if (hash_kind == "fnv32a") { + hash_value = fnv32a(data, file_size); + } else if (hash_kind == "fnv64a") { + hash_value = fnv64a(data, file_size); + } else if (hash_kind == "murmur32") { + hash_value = gb_murmur32(data, file_size); + } else if (hash_kind == "murmur64") { + hash_value = gb_murmur64(data, file_size); + } else { + compiler_error("unhandled hash kind: %.*s", LIT(hash_kind)); + } + string_map_set(&cache->hashes, hash_kind, hash_value); } - gb_free(a, data); - } - - operand->type = t_untyped_integer; - operand->mode = Addressing_Constant; - operand->value = exact_value_u64(hash_value); + operand->type = t_untyped_integer; + operand->mode = Addressing_Constant; + operand->value = exact_value_u64(hash_value); + return true; + } + return false; } else if (name == "load_or") { warning(call, "'#load_or' is deprecated in favour of '#load(path) or_else default'"); diff --git a/src/checker.cpp b/src/checker.cpp index c75fc86af..d01dc5323 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1170,6 +1170,8 @@ void init_checker_info(CheckerInfo *i) { mutex_init(&i->objc_types_mutex); map_init(&i->objc_msgSend_types, a); + mutex_init(&i->load_file_mutex); + string_map_init(&i->load_file_cache, a); } void destroy_checker_info(CheckerInfo *i) { @@ -1205,6 +1207,8 @@ void destroy_checker_info(CheckerInfo *i) { mutex_destroy(&i->objc_types_mutex); map_destroy(&i->objc_msgSend_types); + mutex_init(&i->load_file_mutex); + string_map_destroy(&i->load_file_cache); } CheckerContext make_checker_context(Checker *c) { diff --git a/src/checker.hpp b/src/checker.hpp index f11a00532..badcd93d5 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -287,6 +287,12 @@ struct ObjcMsgData { ObjcMsgKind kind; Type *proc_type; }; +struct LoadFileCache { + String path; + gbFileError file_error; + String data; + StringMap hashes; +}; // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { @@ -363,6 +369,9 @@ struct CheckerInfo { BlockingMutex objc_types_mutex; PtrMap objc_msgSend_types; + + BlockingMutex load_file_mutex; + StringMap load_file_cache; }; struct CheckerContext { -- cgit v1.2.3 From 9eeed9d5bde1348d16d3c3790ba3178f3e0bb09d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 13:35:24 +0100 Subject: Simplify `#load_or` for the time being --- src/check_builtin.cpp | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 70b5a0a13..b0c7f8d4b 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1392,45 +1392,17 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast gb_string_free(str); return false; } - - gbAllocator a = heap_allocator(); - GB_ASSERT(o.value.kind == ExactValue_String); - String base_dir = dir_from_path(get_file_path_string(bd->token.pos.file_id)); String original_string = o.value.value_string; - - BlockingMutex *ignore_mutex = nullptr; - String path = {}; - bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path); - gb_unused(ok); - - char *c_str = alloc_cstring(a, path); - defer (gb_free(a, c_str)); - - - gbFile f = {}; - gbFileError file_err = gb_file_open(&f, c_str); - defer (gb_file_close(&f)); - operand->type = t_u8_slice; operand->mode = Addressing_Constant; - if (file_err == gbFileError_None) { - String result = {}; - isize file_size = cast(isize)gb_file_size(&f); - if (file_size > 0) { - u8 *data = cast(u8 *)gb_alloc(a, file_size+1); - gb_file_read_at(&f, data, file_size, 0); - data[file_size] = '\0'; - result.text = data; - result.len = file_size; - } - - operand->value = exact_value_string(result); + LoadFileCache *cache = nullptr; + if (cache_load_file_directive(c, call, original_string, false, &cache)) { + operand->value = exact_value_string(cache->data); } else { operand->value = default_op.value; } - } else if (name == "assert") { if (ce->args.count != 1 && ce->args.count != 2) { error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count); -- cgit v1.2.3 From 70dc0c15fd244bdc4a769b0d91b50ecc210bca65 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 13:43:35 +0100 Subject: Improve type hint for #load to allow for string types --- src/check_builtin.cpp | 8 ++++++-- src/check_expr.cpp | 14 ++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b0c7f8d4b..122d3a461 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1196,10 +1196,14 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As GB_ASSERT(o.value.kind == ExactValue_String); + operand->type = t_u8_slice; + if (type_hint && is_type_string(type_hint)) { + operand->type = type_hint; + } + operand->mode = Addressing_Constant; + LoadFileCache *cache = nullptr; if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache)) { - operand->type = t_u8_slice; - operand->mode = Addressing_Constant; operand->value = exact_value_string(cache->data); return LoadDirective_Success; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ae459574c..076eaba73 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7435,10 +7435,6 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type // NOTE(bill, 2022-08-11): edge case to handle #load(path) or_else default if (is_load_directive_call(arg)) { LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false); - if (res == LoadDirective_Success) { - *o = x; - return Expr_Expr; - } bool y_is_diverging = false; check_expr_base(c, &y, default_value, x.type); @@ -7468,10 +7464,16 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type if (!y_is_diverging) { check_assignment(c, &y, x.type, name); + if (y.mode != Addressing_Constant) { + error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'"); + } } - o->mode = y.mode; - o->type = y.type; + if (res == LoadDirective_Success) { + *o = x; + } else { + *o = y; + } o->expr = node; return Expr_Expr; -- cgit v1.2.3 From a7c39060038f63b1840f6eb5c0750bdb47e7d3ea Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 14:30:14 +0100 Subject: `#load(path, type)` where `type` can be `string` or `[]T` where `T` is a simple type --- src/check_builtin.cpp | 49 ++++++++++++++++++++++++++++++++++++------ src/llvm_backend_const.cpp | 4 ++-- src/llvm_backend_general.cpp | 48 +++++++++++++++++++++++++++++++++++++++++ src/types.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 122d3a461..36c9ea001 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1169,11 +1169,11 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As String name = bd->name.string; GB_ASSERT(name == "load"); - if (ce->args.count != 1) { + if (ce->args.count != 1 && ce->args.count != 2) { if (ce->args.count == 0) { - error(ce->close, "'#load' expects 1 argument, got 0"); + error(ce->close, "'#%.*s' expects 1 or 2 arguments, got 0", LIT(name)); } else { - error(ce->args[0], "'#load' expects 1 argument, got %td", ce->args.count); + error(ce->args[0], "'#%.*s' expects 1 or 2 arguments, got %td", LIT(name), ce->args.count); } return LoadDirective_Error; @@ -1183,13 +1183,13 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As Operand o = {}; check_expr(c, &o, arg); if (o.mode != Addressing_Constant) { - error(arg, "'#load' expected a constant string argument"); + error(arg, "'#%.*s' expected a constant string argument", LIT(name)); return LoadDirective_Error; } if (!is_type_string(o.type)) { gbString str = type_to_string(o.type); - error(arg, "'#load' expected a constant string, got %s", str); + error(arg, "'#%.*s' expected a constant string, got %s", LIT(name), str); gb_string_free(str); return LoadDirective_Error; } @@ -1197,8 +1197,43 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As GB_ASSERT(o.value.kind == ExactValue_String); operand->type = t_u8_slice; - if (type_hint && is_type_string(type_hint)) { - operand->type = type_hint; + if (ce->args.count == 1) { + if (type_hint && is_type_string(type_hint)) { + operand->type = type_hint; + } + } else if (ce->args.count == 2) { + bool failed = false; + Ast *arg_type = ce->args[1]; + Type *type = check_type(c, arg_type); + if (type != nullptr && type != t_invalid) { + if (is_type_string(type)) { + operand->type = type; + } else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) { + Type *elem = nullptr; + Type *bt = base_type(type); + if (bt->kind == Type_Slice) { + elem = bt->Slice.elem; + } else if (bt->kind == Type_Array) { + elem = bt->Array.elem; + } else if (bt->kind == Type_EnumeratedArray) { + elem = bt->EnumeratedArray.elem; + } + GB_ASSERT(elem != nullptr); + if (is_type_load_safe(elem)) { + operand->type = type; + } else { + failed = true; + } + } else { + failed = true; + } + } + + if (failed) { + gbString type_str = type_to_string(type); + error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str); + gb_string_free(type_str); + } } operand->mode = Addressing_Constant; diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 954778bb6..2d14070e2 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -391,8 +391,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc if (is_type_slice(type)) { if (value.kind == ExactValue_String) { - GB_ASSERT(is_type_u8_slice(type)); - res.value = lb_find_or_add_entity_string_byte_slice(m, value.value_string).value; + GB_ASSERT(is_type_slice(type)); + res.value = lb_find_or_add_entity_string_byte_slice_with_type(m, value.value_string, original_type).value; return res; } else { ast_node(cl, CompoundLit, value.value_compound); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 082163b2f..8704bc7c7 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2523,7 +2523,55 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) res.type = t_u8_slice; return res; } +lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *m, String const &str, Type *slice_type) { + GB_ASSERT(is_type_slice(slice_type)); + LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; + LLVMValueRef data = LLVMConstStringInContext(m->ctx, + cast(char const *)str.text, + cast(unsigned)str.len, + false); + + + char *name = nullptr; + { + isize max_len = 7+8+1; + name = gb_alloc_array(permanent_allocator(), char, max_len); + u32 id = m->gen->global_array_index.fetch_add(1); + isize len = gb_snprintf(name, max_len, "csbs$%x", id); + len -= 1; + } + LLVMTypeRef type = LLVMTypeOf(data); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); + LLVMSetInitializer(global_data, data); + LLVMSetLinkage(global_data, LLVMPrivateLinkage); + LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr); + LLVMSetAlignment(global_data, 1); + LLVMSetGlobalConstant(global_data, true); + i64 data_len = str.len; + LLVMValueRef ptr = nullptr; + if (data_len != 0) { + ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); + } else { + ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); + } + if (!is_type_u8_slice(slice_type)) { + Type *bt = base_type(slice_type); + Type *elem = bt->Slice.elem; + i64 sz = type_size_of(elem); + GB_ASSERT(sz > 0); + ptr = LLVMConstPointerCast(ptr, lb_type(m, alloc_type_pointer(elem))); + data_len /= sz; + } + + LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), data_len, true); + LLVMValueRef values[2] = {ptr, len}; + + lbValue res = {}; + res.value = llvm_const_named_struct(m, slice_type, values, 2); + res.type = slice_type; + return res; +} diff --git a/src/types.cpp b/src/types.cpp index cba27fd6f..1f4804430 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2398,6 +2398,57 @@ bool is_type_simple_compare(Type *t) { return false; } +bool is_type_load_safe(Type *type) { + GB_ASSERT(type != nullptr); + type = core_type(core_array_type(type)); + switch (type->kind) { + case Type_Basic: + return (type->Basic.flags & (BasicFlag_Boolean|BasicFlag_Numeric|BasicFlag_Rune)) != 0; + + case Type_BitSet: + if (type->BitSet.underlying) { + return is_type_load_safe(type->BitSet.underlying); + } + return true; + + case Type_RelativePointer: + case Type_RelativeSlice: + return true; + + case Type_Pointer: + case Type_MultiPointer: + case Type_Slice: + case Type_DynamicArray: + case Type_Proc: + case Type_SoaPointer: + return false; + + case Type_Enum: + case Type_EnumeratedArray: + case Type_Array: + case Type_SimdVector: + case Type_Matrix: + GB_PANIC("should never be hit"); + return false; + + case Type_Struct: + for_array(i, type->Struct.fields) { + if (!is_type_load_safe(type->Struct.fields[i]->type)) { + return false; + } + } + return type_size_of(type) > 0; + case Type_Union: + for_array(i, type->Union.variants) { + if (!is_type_load_safe(type->Union.variants[i])) { + return false; + } + } + return type_size_of(type) > 0; + } + return false; +} + String lookup_subtype_polymorphic_field(Type *dst, Type *src) { Type *prev_src = src; // Type *prev_dst = dst; -- cgit v1.2.3 From cecadce86d8070ee31d193736d331926efec0fff Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 14:42:29 +0100 Subject: Allow for chaining of '#load(path) or_else #load(path)' --- src/check_builtin.cpp | 56 ++++++++++++++++++++++++++------------------------- src/check_expr.cpp | 55 ++++++++++++++++++++++++++------------------------ 2 files changed, 58 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 36c9ea001..687f1694b 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1163,6 +1163,27 @@ bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &origi } +bool is_valid_type_for_load(Type *type) { + if (type == t_invalid) { + return false; + } else if (is_type_string(type)) { + return true; + } else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) { + Type *elem = nullptr; + Type *bt = base_type(type); + if (bt->kind == Type_Slice) { + elem = bt->Slice.elem; + } else if (bt->kind == Type_Array) { + elem = bt->Array.elem; + } else if (bt->kind == Type_EnumeratedArray) { + elem = bt->EnumeratedArray.elem; + } + GB_ASSERT(elem != nullptr); + return is_type_load_safe(elem); + } + return false; +} + LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) { ast_node(ce, CallExpr, call); ast_node(bd, BasicDirective, ce->proc); @@ -1198,42 +1219,23 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As operand->type = t_u8_slice; if (ce->args.count == 1) { - if (type_hint && is_type_string(type_hint)) { + if (type_hint && is_valid_type_for_load(type_hint)) { operand->type = type_hint; } } else if (ce->args.count == 2) { - bool failed = false; Ast *arg_type = ce->args[1]; Type *type = check_type(c, arg_type); - if (type != nullptr && type != t_invalid) { - if (is_type_string(type)) { + if (type != nullptr) { + if (is_valid_type_for_load(type)) { operand->type = type; - } else if (is_type_slice(type) /*|| is_type_array(type) || is_type_enumerated_array(type)*/) { - Type *elem = nullptr; - Type *bt = base_type(type); - if (bt->kind == Type_Slice) { - elem = bt->Slice.elem; - } else if (bt->kind == Type_Array) { - elem = bt->Array.elem; - } else if (bt->kind == Type_EnumeratedArray) { - elem = bt->EnumeratedArray.elem; - } - GB_ASSERT(elem != nullptr); - if (is_type_load_safe(elem)) { - operand->type = type; - } else { - failed = true; - } } else { - failed = true; + gbString type_str = type_to_string(type); + error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str); + gb_string_free(type_str); } } - - if (failed) { - gbString type_str = type_to_string(type); - error(arg_type, "'#%.*s' invalid type, expected a string, or slice of simple types, got %s", LIT(name), type_str); - gb_string_free(type_str); - } + } else { + GB_PANIC("unreachable"); } operand->mode = Addressing_Constant; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 076eaba73..310874139 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7436,36 +7436,39 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type if (is_load_directive_call(arg)) { LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false); - bool y_is_diverging = false; - check_expr_base(c, &y, default_value, x.type); - switch (y.mode) { - case Addressing_NoValue: - if (is_diverging_expr(y.expr)) { - // Allow - y.mode = Addressing_Value; - y_is_diverging = true; - } else { - error_operand_no_value(&y); + // Allow for chaining of '#load(path) or_else #load(path)' + if (!(is_load_directive_call(default_value) && res == LoadDirective_Success)) { + bool y_is_diverging = false; + check_expr_base(c, &y, default_value, x.type); + switch (y.mode) { + case Addressing_NoValue: + if (is_diverging_expr(y.expr)) { + // Allow + y.mode = Addressing_Value; + y_is_diverging = true; + } else { + error_operand_no_value(&y); + y.mode = Addressing_Invalid; + } + break; + case Addressing_Type: + error_operand_not_expression(&y); y.mode = Addressing_Invalid; + break; } - break; - case Addressing_Type: - error_operand_not_expression(&y); - y.mode = Addressing_Invalid; - break; - } - if (y.mode == Addressing_Invalid) { - o->mode = Addressing_Value; - o->type = t_invalid; - o->expr = node; - return Expr_Expr; - } + if (y.mode == Addressing_Invalid) { + o->mode = Addressing_Value; + o->type = t_invalid; + o->expr = node; + return Expr_Expr; + } - if (!y_is_diverging) { - check_assignment(c, &y, x.type, name); - if (y.mode != Addressing_Constant) { - error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'"); + if (!y_is_diverging) { + check_assignment(c, &y, x.type, name); + if (y.mode != Addressing_Constant) { + error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'"); + } } } -- cgit v1.2.3 From 03f683f9e77b82b1239633db08463924785e2630 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 15:19:27 +0100 Subject: Improve emit store for large constants --- src/llvm_backend_general.cpp | 46 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 082163b2f..bcbd041ae 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -567,6 +567,13 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu } } +unsigned lb_try_get_alignment(LLVMValueRef addr_ptr, unsigned default_alignment) { + if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) { + return LLVMGetAlignment(addr_ptr); + } + return default_alignment; +} + bool lb_try_update_alignment(LLVMValueRef addr_ptr, unsigned alignment) { if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) { if (LLVMGetAlignment(addr_ptr) < alignment) { @@ -914,16 +921,35 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { enum {MAX_STORE_SIZE = 64}; - if (LLVMIsALoadInst(value.value) && lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) { - LLVMValueRef dst_ptr = ptr.value; - LLVMValueRef src_ptr = LLVMGetOperand(value.value, 0); - src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), ""); - - LLVMBuildMemMove(p->builder, - dst_ptr, 1, - src_ptr, 1, - LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false)); - return; + if (lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) { + if (LLVMIsALoadInst(value.value)) { + LLVMValueRef dst_ptr = ptr.value; + LLVMValueRef src_ptr_original = LLVMGetOperand(value.value, 0); + LLVMValueRef src_ptr = LLVMBuildPointerCast(p->builder, src_ptr_original, LLVMTypeOf(dst_ptr), ""); + + LLVMBuildMemMove(p->builder, + dst_ptr, lb_try_get_alignment(dst_ptr, 1), + src_ptr, lb_try_get_alignment(src_ptr_original, 1), + LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false)); + return; + } else if (LLVMIsConstant(value.value)) { + lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr); + LLVMValueRef global_data = addr.addr.value; + // make it truly private data + LLVMSetLinkage(global_data, LLVMPrivateLinkage); + LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr); + LLVMSetGlobalConstant(global_data, true); + + LLVMValueRef dst_ptr = ptr.value; + LLVMValueRef src_ptr = global_data; + src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), ""); + + LLVMBuildMemMove(p->builder, + dst_ptr, lb_try_get_alignment(dst_ptr, 1), + src_ptr, lb_try_get_alignment(global_data, 1), + LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false)); + return; + } } if (lb_is_type_proc_recursive(a)) { -- cgit v1.2.3 From 0f3562ef021fc1042d651d5ad1f834af67d2d001 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 16:01:46 +0100 Subject: Improve compound literal generation for array-like types --- src/llvm_backend_expr.cpp | 2210 ++++++++++++++++++++---------------------- src/llvm_backend_general.cpp | 3 +- 2 files changed, 1041 insertions(+), 1172 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 7568f975e..0cf2b3c03 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3491,1415 +3491,1283 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { return addr; } +void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice const &elems, Array *temp_data, Type *compound_type) { + Type *bt = base_type(compound_type); + Type *et = nullptr; + switch (bt->kind) { + case Type_Array: et = bt->Array.elem; break; + case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; + case Type_Slice: et = bt->Slice.elem; break; + case Type_BitSet: et = bt->BitSet.elem; break; + case Type_DynamicArray: et = bt->DynamicArray.elem; break; + case Type_SimdVector: et = bt->SimdVector.elem; break; + case Type_Matrix: et = bt->Matrix.elem; break; + } + GB_ASSERT(et != nullptr); + + + // NOTE(bill): Separate value, gep, store into their own chunks + for_array(i, elems) { + Ast *elem = elems[i]; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (lb_is_elem_const(fv->value, et)) { + continue; + } + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } -lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { - switch (expr->kind) { - case_ast_node(i, Implicit, expr); - lbAddr v = {}; - switch (i->kind) { - case Token_context: - v = lb_find_or_generate_context_ptr(p); - break; - } - - GB_ASSERT(v.addr.value != nullptr); - return v; - case_end; - - case_ast_node(i, Ident, expr); - if (is_blank_ident(expr)) { - lbAddr val = {}; - return val; - } - String name = i->token.string; - Entity *e = entity_of_node(expr); - return lb_build_addr_from_entity(p, e, expr); - case_end; + lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); - case_ast_node(se, SelectorExpr, expr); - Ast *sel_node = unparen_expr(se->selector); - if (sel_node->kind == Ast_Ident) { - String selector = sel_node->Ident.token.string; - TypeAndValue tav = type_and_value_of_expr(se->expr); + GB_ASSERT((hi-lo) > 0); - if (tav.mode == Addressing_Invalid) { - // NOTE(bill): Imports - Entity *imp = entity_of_node(se->expr); - if (imp != nullptr) { - GB_ASSERT(imp->kind == Entity_ImportName); + enum {MAX_ELEMENT_AMOUNT = 32}; + if ((hi-lo) <= MAX_ELEMENT_AMOUNT) { + for (i64 k = lo; k < hi; k++) { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = k; + array_add(temp_data, data); + } + } else { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = lo; + data.elem_length = hi-lo; + array_add(temp_data, data); } - return lb_build_addr(p, unparen_expr(se->selector)); + } else { + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); + GB_ASSERT(!is_type_tuple(value.type)); + + lbCompoundLitElemTempData data = {}; + data.value = value; + data.expr = fv->value; + data.elem_index = cast(i32)index; + array_add(temp_data, data); } + } else { + if (lb_is_elem_const(elem, et)) { + continue; + } - Type *type = base_type(tav.type); - if (tav.mode == Addressing_Type) { // Addressing_Type - Selection sel = lookup_field(tav.type, selector, true); - if (sel.pseudo_field) { - GB_ASSERT(sel.entity->kind == Entity_Procedure); - return lb_addr(lb_find_value_from_entity(p->module, sel.entity)); + lbValue field_expr = lb_build_expr(p, elem); + GB_ASSERT(!is_type_tuple(field_expr.type)); + + lbValue ev = lb_emit_conv(p, field_expr, et); + + lbCompoundLitElemTempData data = {}; + data.value = ev; + data.elem_index = cast(i32)i; + array_add(temp_data, data); + } + } +} +void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array &temp_data) { + for_array(i, temp_data) { + auto td = temp_data[i]; + if (td.value.value != nullptr) { + if (td.elem_length > 0) { + auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32); + { + lbValue dst = temp_data[i].gep; + dst = lb_emit_ptr_offset(p, dst, loop_data.idx); + lb_emit_store(p, dst, temp_data[i].value); } - GB_PANIC("Unreachable %.*s", LIT(selector)); + lb_loop_end(p, loop_data); + } else { + lb_emit_store(p, temp_data[i].gep, temp_data[i].value); } + } + } +} - if (se->swizzle_count > 0) { - Type *array_type = base_type(type_deref(tav.type)); - GB_ASSERT(array_type->kind == Type_Array); - u8 swizzle_count = se->swizzle_count; - u8 swizzle_indices_raw = se->swizzle_indices; - u8 swizzle_indices[4] = {}; - for (u8 i = 0; i < swizzle_count; i++) { - u8 index = swizzle_indices_raw>>(i*2) & 3; - swizzle_indices[i] = index; - } - lbValue a = {}; - if (is_type_pointer(tav.type)) { - a = lb_build_expr(p, se->expr); - } else { - lbAddr addr = lb_build_addr(p, se->expr); - a = lb_addr_get_ptr(p, addr); - } - GB_ASSERT(is_type_array(expr->tav.type)); - return lb_addr_swizzle(a, expr->tav.type, swizzle_count, swizzle_indices); - } +lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { + ast_node(cl, CompoundLit, expr); - Selection sel = lookup_field(type, selector, false); - GB_ASSERT(sel.entity != nullptr); - if (sel.pseudo_field) { - GB_ASSERT(sel.entity->kind == Entity_Procedure); - Entity *e = entity_of_node(sel_node); - return lb_addr(lb_find_value_from_entity(p->module, e)); - } + Type *type = type_of_expr(expr); + Type *bt = base_type(type); - { - lbAddr addr = lb_build_addr(p, se->expr); - if (addr.kind == lbAddr_Map) { - lbValue v = lb_addr_load(p, addr); - lbValue a = lb_address_from_load_or_generate_local(p, v); - a = lb_emit_deep_field_gep(p, a, sel); - return lb_addr(a); - } else if (addr.kind == lbAddr_Context) { - GB_ASSERT(sel.index.count > 0); - if (addr.ctx.sel.index.count >= 0) { - sel = selection_combine(addr.ctx.sel, sel); - } - addr.ctx.sel = sel; - addr.kind = lbAddr_Context; - return addr; - } else if (addr.kind == lbAddr_SoaVariable) { - lbValue index = addr.soa.index; - i32 first_index = sel.index[0]; - Selection sub_sel = sel; - sub_sel.index.data += 1; - sub_sel.index.count -= 1; + lbAddr v = lb_add_local_generated(p, type, true); - lbValue arr = lb_emit_struct_ep(p, addr.addr, first_index); + Type *et = nullptr; + switch (bt->kind) { + case Type_Array: et = bt->Array.elem; break; + case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; + case Type_Slice: et = bt->Slice.elem; break; + case Type_BitSet: et = bt->BitSet.elem; break; + case Type_SimdVector: et = bt->SimdVector.elem; break; + case Type_Matrix: et = bt->Matrix.elem; break; + } - Type *t = base_type(type_deref(addr.addr.type)); - GB_ASSERT(is_type_soa_struct(t)); + String proc_name = {}; + if (p->entity) { + proc_name = p->entity->token.string; + } + TokenPos pos = ast_token(expr).pos; - if (addr.soa.index_expr != nullptr && (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) { - lbValue len = lb_soa_struct_len(p, addr.addr); - lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); - } + switch (bt->kind) { + default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; - lbValue item = {}; + case Type_Struct: { + // TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment. + // NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR + bool is_raw_union = is_type_raw_union(bt); + GB_ASSERT(is_type_struct(bt) || is_raw_union); + TypeStruct *st = &bt->Struct; + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + lbValue comp_lit_ptr = lb_addr_get_ptr(p, v); - if (t->Struct.soa_kind == StructSoa_Fixed) { - item = lb_emit_array_ep(p, arr, index); - } else { - item = lb_emit_ptr_offset(p, lb_emit_load(p, arr), index); - } - if (sub_sel.index.count > 0) { - item = lb_emit_deep_field_gep(p, item, sub_sel); - } - return lb_addr(item); - } else if (addr.kind == lbAddr_Swizzle) { - GB_ASSERT(sel.index.count > 0); - // NOTE(bill): just patch the index in place - sel.index[0] = addr.swizzle.indices[sel.index[0]]; - } else if (addr.kind == lbAddr_SwizzleLarge) { - GB_ASSERT(sel.index.count > 0); - // NOTE(bill): just patch the index in place - sel.index[0] = addr.swizzle.indices[sel.index[0]]; + for_array(field_index, cl->elems) { + Ast *elem = cl->elems[field_index]; + + lbValue field_expr = {}; + Entity *field = nullptr; + isize index = field_index; + + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + String name = fv->field->Ident.token.string; + Selection sel = lookup_field(bt, name, false); + index = sel.index[0]; + elem = fv->value; + TypeAndValue tav = type_and_value_of_expr(elem); + } else { + TypeAndValue tav = type_and_value_of_expr(elem); + Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_index); + index = sel.index[0]; } - lbValue a = lb_addr_get_ptr(p, addr); - a = lb_emit_deep_field_gep(p, a, sel); - return lb_addr(a); - } - } else { - GB_PANIC("Unsupported selector expression"); - } - case_end; + field = st->fields[index]; + Type *ft = field->type; + if (!is_raw_union && !is_type_typeid(ft) && lb_is_elem_const(elem, ft)) { + continue; + } - case_ast_node(se, SelectorCallExpr, expr); - lbValue e = lb_build_expr(p, expr); - return lb_addr(lb_address_from_load_or_generate_local(p, e)); - case_end; + field_expr = lb_build_expr(p, elem); - case_ast_node(ta, TypeAssertion, expr); - TokenPos pos = ast_token(expr).pos; - lbValue e = lb_build_expr(p, ta->expr); - Type *t = type_deref(e.type); - if (is_type_union(t)) { - Type *type = type_of_expr(expr); - lbAddr v = lb_add_local_generated(p, type, false); - lb_addr_store(p, v, lb_emit_union_cast(p, lb_build_expr(p, ta->expr), type, pos)); - return v; - } else if (is_type_any(t)) { - Type *type = type_of_expr(expr); - return lb_emit_any_cast_addr(p, lb_build_expr(p, ta->expr), type, pos); - } else { - GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type)); + lbValue gep = {}; + if (is_raw_union) { + gep = lb_emit_conv(p, comp_lit_ptr, alloc_type_pointer(ft)); + } else { + gep = lb_emit_struct_ep(p, comp_lit_ptr, cast(i32)index); + } + + Type *fet = field_expr.type; + GB_ASSERT(fet->kind != Type_Tuple); + + // HACK TODO(bill): THIS IS A MASSIVE HACK!!!! + if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) { + GB_ASSERT_MSG(union_variant_index(ft, fet) > 0, "%s", type_to_string(fet)); + + lb_emit_store_union_variant(p, gep, field_expr, fet); + } else { + lbValue fv = lb_emit_conv(p, field_expr, ft); + lb_emit_store(p, gep, fv); + } + } } - case_end; + break; + } - case_ast_node(ue, UnaryExpr, expr); - switch (ue->op.kind) { - case Token_And: { - lbValue ptr = lb_build_expr(p, expr); - return lb_addr(lb_address_from_load_or_generate_local(p, ptr)); + case Type_Map: { + if (cl->elems.count == 0) { + break; } - default: - GB_PANIC("Invalid unary expression for lb_build_addr"); + GB_ASSERT(!build_context.no_dynamic_literals); + { + auto args = array_make(permanent_allocator(), 3); + args[0] = lb_gen_map_header(p, v.addr, type); + args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count); + args[2] = lb_emit_source_code_location(p, proc_name, pos); + lb_emit_runtime_call(p, "__dynamic_map_reserve", args); } - case_end; - case_ast_node(be, BinaryExpr, expr); - lbValue v = lb_build_expr(p, expr); - Type *t = v.type; - if (is_type_pointer(t)) { - return lb_addr(v); + for_array(field_index, cl->elems) { + Ast *elem = cl->elems[field_index]; + ast_node(fv, FieldValue, elem); + + lbValue key = lb_build_expr(p, fv->field); + lbValue value = lb_build_expr(p, fv->value); + lb_insert_dynamic_map_key_and_value(p, v, type, key, value, elem); } - return lb_addr(lb_address_from_load_or_generate_local(p, v)); - case_end; + break; + } - case_ast_node(ie, IndexExpr, expr); - Type *t = base_type(type_of_expr(ie->expr)); + case Type_Array: { + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - bool deref = is_type_pointer(t); - t = base_type(type_deref(t)); - if (is_type_soa_struct(t)) { - // SOA STRUCTURES!!!! - lbValue val = lb_build_addr_ptr(p, ie->expr); - if (deref) { - val = lb_emit_load(p, val); + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); + + lbValue dst_ptr = lb_addr_get_ptr(p, v); + for_array(i, temp_data) { + i32 index = cast(i32)(temp_data[i].elem_index); + temp_data[i].gep = lb_emit_array_epi(p, dst_ptr, index); } - lbValue index = lb_build_expr(p, ie->index); - return lb_addr_soa_variable(val, index, ie->index); + lb_build_addr_compound_lit_assign_array(p, temp_data); } + break; + } + case Type_EnumeratedArray: { + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - if (ie->expr->tav.mode == Addressing_SoaVariable) { - // SOA Structures for slices/dynamic arrays - GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); - - lbValue field = lb_build_expr(p, ie->expr); - lbValue index = lb_build_expr(p, ie->index); + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); - 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 dst_ptr = lb_addr_get_ptr(p, v); + i64 index_offset = exact_value_to_i64(*bt->EnumeratedArray.min_value); + for_array(i, temp_data) { + i32 index = cast(i32)(temp_data[i].elem_index - index_offset); + temp_data[i].gep = lb_emit_array_epi(p, dst_ptr, index); + } - // lbValue a = {}; - // a.value = LLVMGetOperand(field.value, 0); - // a.type = alloc_type_pointer(field.type); + lb_build_addr_compound_lit_assign_array(p, temp_data); + } + break; + } + case Type_Slice: { + if (cl->elems.count > 0) { + lbValue slice = lb_const_value(p->module, type, exact_value_compound(expr)); - // irInstr *b = &a->Instr; - // GB_ASSERT(b->kind == irInstr_StructElementPtr); - // lbValue base_struct = b->StructElementPtr.address; + lbValue data = lb_slice_elem(p, slice); - // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct)))); - // lbValue len = ir_soa_struct_len(p, base_struct); - // lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - lbValue val = lb_emit_ptr_offset(p, field, index); - return lb_addr(val); - } + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr)); + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); - if (is_type_map(t)) { - lbAddr map_addr = lb_build_addr(p, ie->expr); - lbValue map_val = lb_addr_load(p, map_addr); - if (deref) { - map_val = lb_emit_load(p, map_val); + for_array(i, temp_data) { + temp_data[i].gep = lb_emit_ptr_offset(p, data, lb_const_int(p->module, t_int, temp_data[i].elem_index)); } - lbValue key = lb_build_expr(p, ie->index); - key = lb_emit_conv(p, key, t->Map.key); + lb_build_addr_compound_lit_assign_array(p, temp_data); - Type *result_type = type_of_expr(expr); - lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val); - return lb_addr_map(map_ptr, key, t, result_type); - } + { + lbValue count = {}; + count.type = t_int; - switch (t->kind) { - case Type_Array: { - lbValue array = {}; - array = lb_build_addr_ptr(p, ie->expr); - if (deref) { - array = lb_emit_load(p, array); + if (lb_is_const(slice)) { + unsigned indices[1] = {1}; + count.value = LLVMConstExtractValue(slice.value, indices, gb_count_of(indices)); + } else { + count.value = LLVMBuildExtractValue(p->builder, slice.value, 1, ""); + } + lb_fill_slice(p, v, data, count); } - lbValue index = lb_build_expr(p, ie->index); - index = lb_emit_conv(p, index, t_int); - lbValue elem = lb_emit_array_ep(p, array, index); + } + break; + } - auto index_tv = type_and_value_of_expr(ie->index); - if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->Array.count); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return lb_addr(elem); + case Type_DynamicArray: { + if (cl->elems.count == 0) { + break; } + GB_ASSERT(!build_context.no_dynamic_literals); - case Type_EnumeratedArray: { - lbValue array = {}; - array = lb_build_addr_ptr(p, ie->expr); - if (deref) { - array = lb_emit_load(p, array); - } + Type *et = bt->DynamicArray.elem; + lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); + lbValue align = lb_const_int(p->module, t_int, type_align_of(et)); - Type *index_type = t->EnumeratedArray.index; + i64 item_count = gb_max(cl->max_count, cl->elems.count); + { - auto index_tv = type_and_value_of_expr(ie->index); + auto args = array_make(permanent_allocator(), 5); + args[0] = lb_emit_conv(p, lb_addr_get_ptr(p, v), t_rawptr); + args[1] = size; + args[2] = align; + args[3] = lb_const_int(p->module, t_int, item_count); + args[4] = lb_emit_source_code_location(p, proc_name, pos); + lb_emit_runtime_call(p, "__dynamic_array_reserve", args); + } - lbValue index = {}; - if (compare_exact_values(Token_NotEq, *t->EnumeratedArray.min_value, exact_value_i64(0))) { - if (index_tv.mode == Addressing_Constant) { - ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value); - index = lb_const_value(p->module, index_type, idx); - } else { - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type); - } - } else { - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - } + lbValue items = lb_generate_local_array(p, et, item_count); - lbValue elem = lb_emit_array_ep(p, array, index); + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); - if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->EnumeratedArray.count); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return lb_addr(elem); + for_array(i, temp_data) { + temp_data[i].gep = lb_emit_array_epi(p, items, temp_data[i].elem_index); } + lb_build_addr_compound_lit_assign_array(p, temp_data); - case Type_Slice: { - lbValue slice = {}; - slice = lb_build_expr(p, ie->expr); - if (deref) { - slice = lb_emit_load(p, slice); - } - lbValue elem = lb_slice_elem(p, slice); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lbValue len = lb_slice_len(p, slice); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); + { + auto args = array_make(permanent_allocator(), 6); + args[0] = lb_emit_conv(p, v.addr, t_rawptr); + args[1] = size; + args[2] = align; + args[3] = lb_emit_conv(p, items, t_rawptr); + args[4] = lb_const_int(p->module, t_int, item_count); + args[5] = lb_emit_source_code_location(p, proc_name, pos); + lb_emit_runtime_call(p, "__dynamic_array_append", args); } + break; + } - case Type_MultiPointer: { - lbValue multi_ptr = {}; - multi_ptr = lb_build_expr(p, ie->expr); - if (deref) { - multi_ptr = lb_emit_load(p, multi_ptr); - } - lbValue index = lb_build_expr(p, ie->index); - lbValue v = {}; + case Type_Basic: { + GB_ASSERT(is_type_any(bt)); + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); + String field_names[2] = { + str_lit("data"), + str_lit("id"), + }; + Type *field_types[2] = { + t_rawptr, + t_typeid, + }; - LLVMValueRef indices[1] = {index.value}; - v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, t->MultiPointer.elem), multi_ptr.value, indices, 1, "foo"); - v.type = alloc_type_pointer(t->MultiPointer.elem); - return lb_addr(v); - } + for_array(field_index, cl->elems) { + Ast *elem = cl->elems[field_index]; - case Type_RelativeSlice: { - lbAddr slice_addr = {}; - if (deref) { - slice_addr = lb_addr(lb_build_expr(p, ie->expr)); - } else { - slice_addr = lb_build_addr(p, ie->expr); - } - lbValue slice = lb_addr_load(p, slice_addr); + lbValue field_expr = {}; + isize index = field_index; - lbValue elem = lb_slice_elem(p, slice); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lbValue len = lb_slice_len(p, slice); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); - } + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); + index = sel.index[0]; + elem = fv->value; + } else { + TypeAndValue tav = type_and_value_of_expr(elem); + Selection sel = lookup_field(bt, field_names[field_index], false); + index = sel.index[0]; + } - case Type_DynamicArray: { - lbValue dynamic_array = {}; - dynamic_array = lb_build_expr(p, ie->expr); - if (deref) { - dynamic_array = lb_emit_load(p, dynamic_array); - } - lbValue elem = lb_dynamic_array_elem(p, dynamic_array); - lbValue len = lb_dynamic_array_len(p, dynamic_array); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); - } - - case Type_Matrix: { - lbValue matrix = {}; - matrix = lb_build_addr_ptr(p, ie->expr); - if (deref) { - matrix = lb_emit_load(p, matrix); - } - lbValue index = lb_build_expr(p, ie->index); - index = lb_emit_conv(p, index, t_int); - lbValue elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index); - elem = lb_emit_conv(p, elem, alloc_type_pointer(type_of_expr(expr))); + field_expr = lb_build_expr(p, elem); - auto index_tv = type_and_value_of_expr(ie->index); - if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->Matrix.column_count); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); + GB_ASSERT(field_expr.type->kind != Type_Tuple); + + Type *ft = field_types[index]; + lbValue fv = lb_emit_conv(p, field_expr, ft); + lbValue gep = lb_emit_struct_ep(p, lb_addr_get_ptr(p, v), cast(i32)index); + lb_emit_store(p, gep, fv); } - return lb_addr(elem); } + break; + } - case Type_Basic: { // Basic_string - lbValue str; - lbValue elem; - lbValue len; - lbValue index; + 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))); - str = lb_build_expr(p, ie->expr); - if (deref) { - str = lb_emit_load(p, str); - } - elem = lb_string_elem(p, str); - len = lb_string_len(p, str); + lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower)); + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + GB_ASSERT(elem->kind != Ast_FieldValue); - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); + if (lb_is_elem_const(elem, et)) { + continue; + } - return lb_addr(lb_emit_ptr_offset(p, elem, index)); - } - } - case_end; - - case_ast_node(ie, MatrixIndexExpr, expr); - Type *t = base_type(type_of_expr(ie->expr)); + lbValue expr = lb_build_expr(p, elem); + GB_ASSERT(expr.type->kind != Type_Tuple); - bool deref = is_type_pointer(t); - t = base_type(type_deref(t)); - - lbValue m = {}; - m = lb_build_addr_ptr(p, ie->expr); - if (deref) { - m = lb_emit_load(p, m); - } - lbValue row_index = lb_build_expr(p, ie->row_index); - lbValue column_index = lb_build_expr(p, ie->column_index); - row_index = lb_emit_conv(p, row_index, t_int); - column_index = lb_emit_conv(p, column_index, t_int); - lbValue elem = lb_emit_matrix_ep(p, m, row_index, column_index); + 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); - auto row_index_tv = type_and_value_of_expr(ie->row_index); - auto column_index_tv = type_and_value_of_expr(ie->column_index); - if (row_index_tv.mode != Addressing_Constant || column_index_tv.mode != Addressing_Constant) { - lbValue row_count = lb_const_int(p->module, t_int, t->Matrix.row_count); - lbValue column_count = lb_const_int(p->module, t_int, t->Matrix.column_count); - lb_emit_matrix_bounds_check(p, ast_token(ie->row_index), row_index, column_index, row_count, column_count); + 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); + } } - return lb_addr(elem); - - - case_end; - - case_ast_node(se, SliceExpr, expr); + break; + } - lbValue low = lb_const_int(p->module, t_int, 0); - lbValue high = {}; + case Type_Matrix: { + if (cl->elems.count > 0) { + lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - if (se->low != nullptr) { - low = lb_correct_endianness(p, lb_build_expr(p, se->low)); - } - if (se->high != nullptr) { - high = lb_correct_endianness(p, lb_build_expr(p, se->high)); - } + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - bool no_indices = se->low == nullptr && se->high == nullptr; + // NOTE(bill): Separate value, gep, store into their own chunks + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; - lbAddr addr = lb_build_addr(p, se->expr); - lbValue base = lb_addr_load(p, addr); - Type *type = base_type(base.type); + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (lb_is_elem_const(fv->value, et)) { + continue; + } + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); - if (is_type_pointer(type)) { - type = base_type(type_deref(type)); - addr = lb_addr(base); - base = lb_addr_load(p, addr); - } + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } - switch (type->kind) { - case Type_Slice: { - Type *slice_type = type; - lbValue len = lb_slice_len(p, base); - if (high.value == nullptr) high = len; + lbValue value = lb_build_expr(p, fv->value); - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } + for (i64 k = lo; k < hi; k++) { + lbCompoundLitElemTempData data = {}; + data.value = value; - lbValue elem = lb_emit_ptr_offset(p, lb_slice_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, k); + array_add(&temp_data, data); + } - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } + } else { + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); - case Type_RelativeSlice: - GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the lb_addr_load"); - break; + lbValue value = lb_build_expr(p, fv->value); + lbCompoundLitElemTempData data = {}; + data.value = lb_emit_conv(p, value, et); + data.expr = fv->value; - case Type_DynamicArray: { - Type *elem_type = type->DynamicArray.elem; - Type *slice_type = alloc_type_slice(elem_type); + data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, index); + array_add(&temp_data, data); + } - lbValue len = lb_dynamic_array_len(p, base); - if (high.value == nullptr) high = len; + } else { + if (lb_is_elem_const(elem, et)) { + continue; + } + lbCompoundLitElemTempData data = {}; + data.expr = elem; + data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, i); + array_add(&temp_data, data); + } + } - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + for_array(i, temp_data) { + temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index); } - lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + for_array(i, temp_data) { + lbValue field_expr = temp_data[i].value; + Ast *expr = temp_data[i].expr; - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } + auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - case Type_MultiPointer: { - lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false); - if (se->high == nullptr) { - lbValue offset = base; - LLVMValueRef indices[1] = {low.value}; - offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, ""); - lb_addr_store(p, res, offset); - } else { - low = lb_emit_conv(p, low, t_int); - high = lb_emit_conv(p, high, t_int); - - lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); + if (field_expr.value == nullptr) { + field_expr = lb_build_expr(p, expr); + } + Type *t = field_expr.type; + GB_ASSERT(t->kind != Type_Tuple); + lbValue ev = lb_emit_conv(p, field_expr, et); - LLVMValueRef indices[1] = {low.value}; - LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, ""); - LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, ""); - - LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value; - LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value; - LLVMBuildStore(p->builder, ptr, gep0); - LLVMBuildStore(p->builder, len, gep1); + if (!p->copy_elision_hint.used) { + temp_data[i].value = ev; + } + + lb_reset_copy_elision_hint(p, prev_hint); + } + + for_array(i, temp_data) { + if (temp_data[i].value.value != nullptr) { + lb_emit_store(p, temp_data[i].gep, temp_data[i].value); + } } - return res; } + break; + } - case Type_Array: { - Type *slice_type = alloc_type_slice(type->Array.elem); - lbValue len = lb_const_int(p->module, t_int, type->Array.count); + case Type_SimdVector: { + if (cl->elems.count > 0) { + lbValue vector_value = lb_const_value(p->module, type, exact_value_compound(expr)); + defer (lb_addr_store(p, v, vector_value)); - if (high.value == nullptr) high = len; + auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; - bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; + // NOTE(bill): Separate value, store into their own chunks + for_array(i, cl->elems) { + Ast *elem = cl->elems[i]; + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + if (lb_is_elem_const(fv->value, et)) { + continue; + } + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); - if (!low_const || !high_const) { - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } + + lbValue value = lb_build_expr(p, fv->value); + + for (i64 k = lo; k < hi; k++) { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = cast(i32)k; + array_add(&temp_data, data); + } + + } else { + auto tav = fv->field->tav; + GB_ASSERT(tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(tav.value); + + lbValue value = lb_build_expr(p, fv->value); + lbCompoundLitElemTempData data = {}; + data.value = lb_emit_conv(p, value, et); + data.expr = fv->value; + data.elem_index = cast(i32)index; + array_add(&temp_data, data); + } + + } else { + if (lb_is_elem_const(elem, et)) { + continue; + } + lbCompoundLitElemTempData data = {}; + data.expr = elem; + data.elem_index = cast(i32)i; + array_add(&temp_data, data); } } - lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } - case Type_Basic: { - GB_ASSERT(type == t_string); - lbValue len = lb_string_len(p, base); - if (high.value == nullptr) high = len; + for_array(i, temp_data) { + lbValue field_expr = temp_data[i].value; + Ast *expr = temp_data[i].expr; - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); + + if (field_expr.value == nullptr) { + field_expr = lb_build_expr(p, expr); + } + Type *t = field_expr.type; + GB_ASSERT(t->kind != Type_Tuple); + lbValue ev = lb_emit_conv(p, field_expr, et); + + if (!p->copy_elision_hint.used) { + temp_data[i].value = ev; + } + + lb_reset_copy_elision_hint(p, prev_hint); } - lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lbAddr str = lb_add_local_generated(p, t_string, false); - lb_fill_string(p, str, elem, new_len); - return str; + // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` + // might be a better option + + for_array(i, temp_data) { + if (temp_data[i].value.value != nullptr) { + LLVMValueRef index = lb_const_int(p->module, t_u32, temp_data[i].elem_index).value; + vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, temp_data[i].value.value, index, ""); + } + } } + break; + } + } + return v; +} - case Type_Struct: - if (is_type_soa_struct(type)) { - lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr)); - if (high.value == nullptr) high = len; - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); +lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { + switch (expr->kind) { + case_ast_node(i, Implicit, expr); + lbAddr v = {}; + switch (i->kind) { + case Token_context: + v = lb_find_or_generate_context_ptr(p); + break; + } + + GB_ASSERT(v.addr.value != nullptr); + return v; + case_end; + + case_ast_node(i, Ident, expr); + if (is_blank_ident(expr)) { + lbAddr val = {}; + return val; + } + String name = i->token.string; + Entity *e = entity_of_node(expr); + return lb_build_addr_from_entity(p, e, expr); + case_end; + + case_ast_node(se, SelectorExpr, expr); + Ast *sel_node = unparen_expr(se->selector); + if (sel_node->kind == Ast_Ident) { + String selector = sel_node->Ident.token.string; + TypeAndValue tav = type_and_value_of_expr(se->expr); + + if (tav.mode == Addressing_Invalid) { + // NOTE(bill): Imports + Entity *imp = entity_of_node(se->expr); + if (imp != nullptr) { + GB_ASSERT(imp->kind == Entity_ImportName); } - #if 1 + return lb_build_addr(p, unparen_expr(se->selector)); + } - lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true); - if (type->Struct.soa_kind == StructSoa_Fixed) { - i32 field_count = cast(i32)type->Struct.fields.count; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); - field_src = lb_emit_array_ep(p, field_src, low); - lb_emit_store(p, field_dst, field_src); - } - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); - } else if (type->Struct.soa_kind == StructSoa_Slice) { - if (no_indices) { - lb_addr_store(p, dst, base); - } else { - i32 field_count = cast(i32)type->Struct.fields.count - 1; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ev(p, base, i); - field_src = lb_emit_ptr_offset(p, field_src, low); - lb_emit_store(p, field_dst, field_src); - } + Type *type = base_type(tav.type); + if (tav.mode == Addressing_Type) { // Addressing_Type + Selection sel = lookup_field(tav.type, selector, true); + if (sel.pseudo_field) { + GB_ASSERT(sel.entity->kind == Entity_Procedure); + return lb_addr(lb_find_value_from_entity(p->module, sel.entity)); + } + GB_PANIC("Unreachable %.*s", LIT(selector)); + } + if (se->swizzle_count > 0) { + Type *array_type = base_type(type_deref(tav.type)); + GB_ASSERT(array_type->kind == Type_Array); + u8 swizzle_count = se->swizzle_count; + u8 swizzle_indices_raw = se->swizzle_indices; + u8 swizzle_indices[4] = {}; + for (u8 i = 0; i < swizzle_count; i++) { + u8 index = swizzle_indices_raw>>(i*2) & 3; + swizzle_indices[i] = index; + } + lbValue a = {}; + if (is_type_pointer(tav.type)) { + a = lb_build_expr(p, se->expr); + } else { + lbAddr addr = lb_build_addr(p, se->expr); + a = lb_addr_get_ptr(p, addr); + } - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); + GB_ASSERT(is_type_array(expr->tav.type)); + return lb_addr_swizzle(a, expr->tav.type, swizzle_count, swizzle_indices); + } + + Selection sel = lookup_field(type, selector, false); + GB_ASSERT(sel.entity != nullptr); + if (sel.pseudo_field) { + GB_ASSERT(sel.entity->kind == Entity_Procedure); + Entity *e = entity_of_node(sel_node); + return lb_addr(lb_find_value_from_entity(p->module, e)); + } + + { + lbAddr addr = lb_build_addr(p, se->expr); + if (addr.kind == lbAddr_Map) { + lbValue v = lb_addr_load(p, addr); + lbValue a = lb_address_from_load_or_generate_local(p, v); + a = lb_emit_deep_field_gep(p, a, sel); + return lb_addr(a); + } else if (addr.kind == lbAddr_Context) { + GB_ASSERT(sel.index.count > 0); + if (addr.ctx.sel.index.count >= 0) { + sel = selection_combine(addr.ctx.sel, sel); } - } else if (type->Struct.soa_kind == StructSoa_Dynamic) { - i32 field_count = cast(i32)type->Struct.fields.count - 3; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ev(p, base, i); - field_src = lb_emit_ptr_offset(p, field_src, low); - lb_emit_store(p, field_dst, field_src); + addr.ctx.sel = sel; + addr.kind = lbAddr_Context; + return addr; + } else if (addr.kind == lbAddr_SoaVariable) { + lbValue index = addr.soa.index; + i32 first_index = sel.index[0]; + Selection sub_sel = sel; + sub_sel.index.data += 1; + sub_sel.index.count -= 1; + + lbValue arr = lb_emit_struct_ep(p, addr.addr, first_index); + + Type *t = base_type(type_deref(addr.addr.type)); + GB_ASSERT(is_type_soa_struct(t)); + + if (addr.soa.index_expr != nullptr && (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) { + lbValue len = lb_soa_struct_len(p, addr.addr); + lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); } + lbValue item = {}; - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); + if (t->Struct.soa_kind == StructSoa_Fixed) { + item = lb_emit_array_ep(p, arr, index); + } else { + item = lb_emit_ptr_offset(p, lb_emit_load(p, arr), index); + } + if (sub_sel.index.count > 0) { + item = lb_emit_deep_field_gep(p, item, sub_sel); + } + return lb_addr(item); + } else if (addr.kind == lbAddr_Swizzle) { + GB_ASSERT(sel.index.count > 0); + // NOTE(bill): just patch the index in place + sel.index[0] = addr.swizzle.indices[sel.index[0]]; + } else if (addr.kind == lbAddr_SwizzleLarge) { + GB_ASSERT(sel.index.count > 0); + // NOTE(bill): just patch the index in place + sel.index[0] = addr.swizzle.indices[sel.index[0]]; } - return dst; - #endif + lbValue a = lb_addr_get_ptr(p, addr); + a = lb_emit_deep_field_gep(p, a, sel); + return lb_addr(a); } - break; - + } else { + GB_PANIC("Unsupported selector expression"); } + case_end; - GB_PANIC("Unknown slicable type"); + case_ast_node(se, SelectorCallExpr, expr); + lbValue e = lb_build_expr(p, expr); + return lb_addr(lb_address_from_load_or_generate_local(p, e)); case_end; - 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)) { - 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); - return lb_addr_soa_variable(ptr, idx, nullptr); + case_ast_node(ta, TypeAssertion, expr); + TokenPos pos = ast_token(expr).pos; + lbValue e = lb_build_expr(p, ta->expr); + Type *t = type_deref(e.type); + if (is_type_union(t)) { + Type *type = type_of_expr(expr); + lbAddr v = lb_add_local_generated(p, type, false); + lb_addr_store(p, v, lb_emit_union_cast(p, lb_build_expr(p, ta->expr), type, pos)); + return v; + } else if (is_type_any(t)) { + Type *type = type_of_expr(expr); + return lb_emit_any_cast_addr(p, lb_build_expr(p, ta->expr), type, pos); + } else { + GB_PANIC("TODO(bill): type assertion %s", type_to_string(e.type)); } - lbValue addr = lb_build_expr(p, de->expr); - return lb_addr(addr); case_end; - case_ast_node(ce, CallExpr, expr); - BuiltinProcId builtin_id = BuiltinProc_Invalid; - if (ce->proc->tav.mode == Addressing_Builtin) { - Entity *e = entity_of_node(ce->proc); - if (e != nullptr) { - builtin_id = cast(BuiltinProcId)e->Builtin.id; - } else { - builtin_id = BuiltinProc_DIRECTIVE; - } + case_ast_node(ue, UnaryExpr, expr); + switch (ue->op.kind) { + case Token_And: { + lbValue ptr = lb_build_expr(p, expr); + return lb_addr(lb_address_from_load_or_generate_local(p, ptr)); } - auto const &tv = expr->tav; - if (builtin_id == BuiltinProc_swizzle && - is_type_array(tv.type)) { - // NOTE(bill, 2021-08-09): `swizzle` has some bizarre semantics so it needs to be - // specialized here for to be addressable - return lb_build_array_swizzle_addr(p, ce, tv); + default: + GB_PANIC("Invalid unary expression for lb_build_addr"); } - - // NOTE(bill): This is make sure you never need to have an 'array_ev' - lbValue e = lb_build_expr(p, expr); - #if 1 - return lb_addr(lb_address_from_load_or_generate_local(p, e)); - #else - lbAddr v = lb_add_local_generated(p, e.type, false); - lb_addr_store(p, v, e); - return v; - #endif + case_end; + case_ast_node(be, BinaryExpr, expr); + lbValue v = lb_build_expr(p, expr); + Type *t = v.type; + if (is_type_pointer(t)) { + return lb_addr(v); + } + return lb_addr(lb_address_from_load_or_generate_local(p, v)); case_end; - case_ast_node(cl, CompoundLit, expr); - Type *type = type_of_expr(expr); - Type *bt = base_type(type); + case_ast_node(ie, IndexExpr, expr); + Type *t = base_type(type_of_expr(ie->expr)); - lbAddr v = lb_add_local_generated(p, type, true); + bool deref = is_type_pointer(t); + t = base_type(type_deref(t)); + if (is_type_soa_struct(t)) { + // SOA STRUCTURES!!!! + lbValue val = lb_build_addr_ptr(p, ie->expr); + if (deref) { + val = lb_emit_load(p, val); + } - Type *et = nullptr; - switch (bt->kind) { - case Type_Array: et = bt->Array.elem; break; - case Type_EnumeratedArray: et = bt->EnumeratedArray.elem; break; - case Type_Slice: et = bt->Slice.elem; break; - case Type_BitSet: et = bt->BitSet.elem; break; - case Type_SimdVector: et = bt->SimdVector.elem; break; - case Type_Matrix: et = bt->Matrix.elem; break; + lbValue index = lb_build_expr(p, ie->index); + return lb_addr_soa_variable(val, index, ie->index); } - String proc_name = {}; - if (p->entity) { - proc_name = p->entity->token.string; - } - TokenPos pos = ast_token(expr).pos; + if (ie->expr->tav.mode == Addressing_SoaVariable) { + // SOA Structures for slices/dynamic arrays + GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); - switch (bt->kind) { - default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; - - case Type_Struct: { - // TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment. - // NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR - bool is_raw_union = is_type_raw_union(bt); - GB_ASSERT(is_type_struct(bt) || is_raw_union); - TypeStruct *st = &bt->Struct; - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - lbValue comp_lit_ptr = lb_addr_get_ptr(p, v); - - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; - - lbValue field_expr = {}; - Entity *field = nullptr; - isize index = field_index; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - String name = fv->field->Ident.token.string; - Selection sel = lookup_field(bt, name, false); - index = sel.index[0]; - elem = fv->value; - TypeAndValue tav = type_and_value_of_expr(elem); - } else { - TypeAndValue tav = type_and_value_of_expr(elem); - Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_index); - index = sel.index[0]; - } + lbValue field = lb_build_expr(p, ie->expr); + lbValue index = lb_build_expr(p, ie->index); - field = st->fields[index]; - Type *ft = field->type; - if (!is_raw_union && !is_type_typeid(ft) && lb_is_elem_const(elem, ft)) { - continue; - } - field_expr = lb_build_expr(p, elem); + if (!build_context.no_bounds_check) { + // TODO HACK(bill): Clean up this hack to get the length for bounds checking + // GB_ASSERT(LLVMIsALoadInst(field.value)); + + // lbValue a = {}; + // a.value = LLVMGetOperand(field.value, 0); + // a.type = alloc_type_pointer(field.type); + + // irInstr *b = &a->Instr; + // GB_ASSERT(b->kind == irInstr_StructElementPtr); + // lbValue base_struct = b->StructElementPtr.address; + + // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct)))); + // lbValue len = ir_soa_struct_len(p, base_struct); + // lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + lbValue val = lb_emit_ptr_offset(p, field, index); + return lb_addr(val); + } - lbValue gep = {}; - if (is_raw_union) { - gep = lb_emit_conv(p, comp_lit_ptr, alloc_type_pointer(ft)); - } else { - gep = lb_emit_struct_ep(p, comp_lit_ptr, cast(i32)index); - } + GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr)); - Type *fet = field_expr.type; - GB_ASSERT(fet->kind != Type_Tuple); + if (is_type_map(t)) { + lbAddr map_addr = lb_build_addr(p, ie->expr); + lbValue map_val = lb_addr_load(p, map_addr); + if (deref) { + map_val = lb_emit_load(p, map_val); + } - // HACK TODO(bill): THIS IS A MASSIVE HACK!!!! - if (is_type_union(ft) && !are_types_identical(fet, ft) && !is_type_untyped(fet)) { - GB_ASSERT_MSG(union_variant_index(ft, fet) > 0, "%s", type_to_string(fet)); + lbValue key = lb_build_expr(p, ie->index); + key = lb_emit_conv(p, key, t->Map.key); - lb_emit_store_union_variant(p, gep, field_expr, fet); - } else { - lbValue fv = lb_emit_conv(p, field_expr, ft); - lb_emit_store(p, gep, fv); - } - } - } - break; + Type *result_type = type_of_expr(expr); + lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val); + return lb_addr_map(map_ptr, key, t, result_type); } - case Type_Map: { - if (cl->elems.count == 0) { - break; - } - { - auto args = array_make(permanent_allocator(), 3); - args[0] = lb_gen_map_header(p, v.addr, type); - args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count); - args[2] = lb_emit_source_code_location(p, proc_name, pos); - lb_emit_runtime_call(p, "__dynamic_map_reserve", args); + switch (t->kind) { + case Type_Array: { + lbValue array = {}; + array = lb_build_addr_ptr(p, ie->expr); + if (deref) { + array = lb_emit_load(p, array); } - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; - ast_node(fv, FieldValue, elem); + lbValue index = lb_build_expr(p, ie->index); + index = lb_emit_conv(p, index, t_int); + lbValue elem = lb_emit_array_ep(p, array, index); - lbValue key = lb_build_expr(p, fv->field); - lbValue value = lb_build_expr(p, fv->value); - lb_insert_dynamic_map_key_and_value(p, v, type, key, value, elem); + auto index_tv = type_and_value_of_expr(ie->index); + if (index_tv.mode != Addressing_Constant) { + lbValue len = lb_const_int(p->module, t_int, t->Array.count); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); } - break; + return lb_addr(elem); } - case Type_Array: { - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - // NOTE(bill): Separate value, gep, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } - - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); + case Type_EnumeratedArray: { + lbValue array = {}; + array = lb_build_addr_ptr(p, ie->expr); + if (deref) { + array = lb_emit_load(p, array); + } - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } + Type *index_type = t->EnumeratedArray.index; - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } + auto index_tv = type_and_value_of_expr(ie->index); - for_array(i, temp_data) { - temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index); + lbValue index = {}; + if (compare_exact_values(Token_NotEq, *t->EnumeratedArray.min_value, exact_value_i64(0))) { + if (index_tv.mode == Addressing_Constant) { + ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value); + index = lb_const_value(p->module, index_type, idx); + } else { + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type); } + } else { + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + } - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; + lbValue elem = lb_emit_array_ep(p, array, index); - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); + if (index_tv.mode != Addressing_Constant) { + lbValue len = lb_const_int(p->module, t_int, t->EnumeratedArray.count); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + return lb_addr(elem); + } - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); + case Type_Slice: { + lbValue slice = {}; + slice = lb_build_expr(p, ie->expr); + if (deref) { + slice = lb_emit_load(p, slice); + } + lbValue elem = lb_slice_elem(p, slice); + lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lbValue len = lb_slice_len(p, slice); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + lbValue v = lb_emit_ptr_offset(p, elem, index); + return lb_addr(v); + } - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } + case Type_MultiPointer: { + lbValue multi_ptr = {}; + multi_ptr = lb_build_expr(p, ie->expr); + if (deref) { + multi_ptr = lb_emit_load(p, multi_ptr); + } + lbValue index = lb_build_expr(p, ie->index); + lbValue v = {}; - lb_reset_copy_elision_hint(p, prev_hint); - } + LLVMValueRef indices[1] = {index.value}; + v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, t->MultiPointer.elem), multi_ptr.value, indices, 1, "foo"); + v.type = alloc_type_pointer(t->MultiPointer.elem); + return lb_addr(v); + } - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } - } + case Type_RelativeSlice: { + lbAddr slice_addr = {}; + if (deref) { + slice_addr = lb_addr(lb_build_expr(p, ie->expr)); + } else { + slice_addr = lb_build_addr(p, ie->expr); } - break; - } - case Type_EnumeratedArray: { - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - // NOTE(bill): Separate value, gep, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } + lbValue slice = lb_addr_load(p, slice_addr); - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); + lbValue elem = lb_slice_elem(p, slice); + lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lbValue len = lb_slice_len(p, slice); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + lbValue v = lb_emit_ptr_offset(p, elem, index); + return lb_addr(v); + } - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } + case Type_DynamicArray: { + lbValue dynamic_array = {}; + dynamic_array = lb_build_expr(p, ie->expr); + if (deref) { + dynamic_array = lb_emit_load(p, dynamic_array); + } + lbValue elem = lb_dynamic_array_elem(p, dynamic_array); + lbValue len = lb_dynamic_array_len(p, dynamic_array); + lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + lbValue v = lb_emit_ptr_offset(p, elem, index); + return lb_addr(v); + } - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } + case Type_Matrix: { + lbValue matrix = {}; + matrix = lb_build_addr_ptr(p, ie->expr); + if (deref) { + matrix = lb_emit_load(p, matrix); + } + lbValue index = lb_build_expr(p, ie->index); + index = lb_emit_conv(p, index, t_int); + lbValue elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index); + elem = lb_emit_conv(p, elem, alloc_type_pointer(type_of_expr(expr))); + auto index_tv = type_and_value_of_expr(ie->index); + if (index_tv.mode != Addressing_Constant) { + lbValue len = lb_const_int(p->module, t_int, t->Matrix.column_count); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + return lb_addr(elem); + } - i32 index_offset = cast(i32)exact_value_to_i64(*bt->EnumeratedArray.min_value); - for_array(i, temp_data) { - i32 index = temp_data[i].elem_index - index_offset; - temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), index); - } + case Type_Basic: { // Basic_string + lbValue str; + lbValue elem; + lbValue len; + lbValue index; - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; + str = lb_build_expr(p, ie->expr); + if (deref) { + str = lb_emit_load(p, str); + } + elem = lb_string_elem(p, str); + len = lb_string_len(p, str); - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); + return lb_addr(lb_emit_ptr_offset(p, elem, index)); + } + } + case_end; - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } + case_ast_node(ie, MatrixIndexExpr, expr); + Type *t = base_type(type_of_expr(ie->expr)); - lb_reset_copy_elision_hint(p, prev_hint); - } + bool deref = is_type_pointer(t); + t = base_type(type_deref(t)); - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } - } - } - break; + lbValue m = {}; + m = lb_build_addr_ptr(p, ie->expr); + if (deref) { + m = lb_emit_load(p, m); } - case Type_Slice: { - if (cl->elems.count > 0) { - lbValue slice = lb_const_value(p->module, type, exact_value_compound(expr)); - - lbValue data = lb_slice_elem(p, slice); + lbValue row_index = lb_build_expr(p, ie->row_index); + lbValue column_index = lb_build_expr(p, ie->column_index); + row_index = lb_emit_conv(p, row_index, t_int); + column_index = lb_emit_conv(p, column_index, t_int); + lbValue elem = lb_emit_matrix_ep(p, m, row_index, column_index); - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); + auto row_index_tv = type_and_value_of_expr(ie->row_index); + auto column_index_tv = type_and_value_of_expr(ie->column_index); + if (row_index_tv.mode != Addressing_Constant || column_index_tv.mode != Addressing_Constant) { + lbValue row_count = lb_const_int(p->module, t_int, t->Matrix.row_count); + lbValue column_count = lb_const_int(p->module, t_int, t->Matrix.column_count); + lb_emit_matrix_bounds_check(p, ast_token(ie->row_index), row_index, column_index, row_count, column_count); + } + return lb_addr(elem); - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } + case_end; - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } + case_ast_node(se, SliceExpr, expr); - } else { - GB_ASSERT(fv->field->tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(fv->field->tav.value); + lbValue low = lb_const_int(p->module, t_int, 0); + lbValue high = {}; - lbValue field_expr = lb_build_expr(p, fv->value); - GB_ASSERT(!is_type_tuple(field_expr.type)); + if (se->low != nullptr) { + low = lb_correct_endianness(p, lb_build_expr(p, se->low)); + } + if (se->high != nullptr) { + high = lb_correct_endianness(p, lb_build_expr(p, se->high)); + } - lbValue ev = lb_emit_conv(p, field_expr, et); + bool no_indices = se->low == nullptr && se->high == nullptr; - lbCompoundLitElemTempData data = {}; - data.value = ev; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbValue field_expr = lb_build_expr(p, elem); - GB_ASSERT(!is_type_tuple(field_expr.type)); + lbAddr addr = lb_build_addr(p, se->expr); + lbValue base = lb_addr_load(p, addr); + Type *type = base_type(base.type); - lbValue ev = lb_emit_conv(p, field_expr, et); + if (is_type_pointer(type)) { + type = base_type(type_deref(type)); + addr = lb_addr(base); + base = lb_addr_load(p, addr); + } - lbCompoundLitElemTempData data = {}; - data.value = ev; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } + switch (type->kind) { + case Type_Slice: { + Type *slice_type = type; + lbValue len = lb_slice_len(p, base); + if (high.value == nullptr) high = len; - for_array(i, temp_data) { - temp_data[i].gep = lb_emit_ptr_offset(p, data, lb_const_int(p->module, t_int, temp_data[i].elem_index)); - } + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } - for_array(i, temp_data) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } + lbValue elem = lb_emit_ptr_offset(p, lb_slice_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - { - lbValue count = {}; - count.type = t_int; + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } - if (lb_is_const(slice)) { - unsigned indices[1] = {1}; - count.value = LLVMConstExtractValue(slice.value, indices, gb_count_of(indices)); - } else { - count.value = LLVMBuildExtractValue(p->builder, slice.value, 1, ""); - } - lb_fill_slice(p, v, data, count); - } - } + case Type_RelativeSlice: + GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the lb_addr_load"); break; - } case Type_DynamicArray: { - if (cl->elems.count == 0) { - break; - } - Type *et = bt->DynamicArray.elem; - lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); - lbValue align = lb_const_int(p->module, t_int, type_align_of(et)); + Type *elem_type = type->DynamicArray.elem; + Type *slice_type = alloc_type_slice(elem_type); - i64 item_count = gb_max(cl->max_count, cl->elems.count); - { + lbValue len = lb_dynamic_array_len(p, base); + if (high.value == nullptr) high = len; - auto args = array_make(permanent_allocator(), 5); - args[0] = lb_emit_conv(p, lb_addr_get_ptr(p, v), t_rawptr); - args[1] = size; - args[2] = align; - args[3] = lb_const_int(p->module, t_int, 2*item_count); // TODO(bill): Is this too much waste? - args[4] = lb_emit_source_code_location(p, proc_name, pos); - lb_emit_runtime_call(p, "__dynamic_array_reserve", args); + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); } - lbValue items = lb_generate_local_array(p, et, item_count); - // lbValue items = lb_generate_global_array(p->module, et, item_count, str_lit("dacl$"), cast(i64)cast(intptr)expr); - - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } + lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lbValue value = lb_emit_conv(p, lb_build_expr(p, fv->value), et); + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } - for (i64 k = lo; k < hi; k++) { - lbValue ep = lb_emit_array_epi(p, items, cast(i32)k); - lb_emit_store(p, ep, value); - } - } else { - GB_ASSERT(fv->field->tav.mode == Addressing_Constant); + case Type_MultiPointer: { + lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false); + if (se->high == nullptr) { + lbValue offset = base; + LLVMValueRef indices[1] = {low.value}; + offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, ""); + lb_addr_store(p, res, offset); + } else { + low = lb_emit_conv(p, low, t_int); + high = lb_emit_conv(p, high, t_int); - i64 field_index = exact_value_to_i64(fv->field->tav.value); + lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); - lbValue ev = lb_build_expr(p, fv->value); - lbValue value = lb_emit_conv(p, ev, et); - lbValue ep = lb_emit_array_epi(p, items, cast(i32)field_index); - lb_emit_store(p, ep, value); - } - } else { - lbValue value = lb_emit_conv(p, lb_build_expr(p, elem), et); - lbValue ep = lb_emit_array_epi(p, items, cast(i32)i); - lb_emit_store(p, ep, value); - } - } + LLVMValueRef indices[1] = {low.value}; + LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, ""); + LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, ""); - { - auto args = array_make(permanent_allocator(), 6); - args[0] = lb_emit_conv(p, v.addr, t_rawptr); - args[1] = size; - args[2] = align; - args[3] = lb_emit_conv(p, items, t_rawptr); - args[4] = lb_const_int(p->module, t_int, item_count); - args[5] = lb_emit_source_code_location(p, proc_name, pos); - lb_emit_runtime_call(p, "__dynamic_array_append", args); + LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value; + LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value; + LLVMBuildStore(p->builder, ptr, gep0); + LLVMBuildStore(p->builder, len, gep1); } - break; + return res; } - case Type_Basic: { - GB_ASSERT(is_type_any(bt)); - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - String field_names[2] = { - str_lit("data"), - str_lit("id"), - }; - Type *field_types[2] = { - t_rawptr, - t_typeid, - }; - - for_array(field_index, cl->elems) { - Ast *elem = cl->elems[field_index]; - - lbValue field_expr = {}; - isize index = field_index; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - Selection sel = lookup_field(bt, fv->field->Ident.token.string, false); - index = sel.index[0]; - elem = fv->value; - } else { - TypeAndValue tav = type_and_value_of_expr(elem); - Selection sel = lookup_field(bt, field_names[field_index], false); - index = sel.index[0]; - } + case Type_Array: { + Type *slice_type = alloc_type_slice(type->Array.elem); + lbValue len = lb_const_int(p->module, t_int, type->Array.count); - field_expr = lb_build_expr(p, elem); + if (high.value == nullptr) high = len; - GB_ASSERT(field_expr.type->kind != Type_Tuple); + bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; + bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; - Type *ft = field_types[index]; - lbValue fv = lb_emit_conv(p, field_expr, ft); - lbValue gep = lb_emit_struct_ep(p, lb_addr_get_ptr(p, v), cast(i32)index); - lb_emit_store(p, gep, fv); + if (!low_const || !high_const) { + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); } } + lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - break; + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; } - case Type_BitSet: { - i64 sz = type_size_of(type); - if (cl->elems.count > 0 && sz > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - - lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower)); - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - GB_ASSERT(elem->kind != Ast_FieldValue); - - if (lb_is_elem_const(elem, et)) { - continue; - } + case Type_Basic: { + GB_ASSERT(type == t_string); + lbValue len = lb_string_len(p, base); + if (high.value == nullptr) high = len; - lbValue expr = lb_build_expr(p, elem); - GB_ASSERT(expr.type->kind != Type_Tuple); + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } - 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 elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - 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; + lbAddr str = lb_add_local_generated(p, t_string, false); + lb_fill_string(p, str, elem, new_len); + return str; } - - case Type_Matrix: { - if (cl->elems.count > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - // NOTE(bill): Separate value, gep, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, k); - array_add(&temp_data, data); - } - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, index); - array_add(&temp_data, data); - } + case Type_Struct: + if (is_type_soa_struct(type)) { + lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr)); + if (high.value == nullptr) high = len; - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, i); - array_add(&temp_data, data); - } + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); } + #if 1 - for_array(i, temp_data) { - temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index); - } + lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true); + if (type->Struct.soa_kind == StructSoa_Fixed) { + i32 field_count = cast(i32)type->Struct.fields.count; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); + field_src = lb_emit_array_ep(p, field_src, low); + lb_emit_store(p, field_dst, field_src); + } - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); + } else if (type->Struct.soa_kind == StructSoa_Slice) { + if (no_indices) { + lb_addr_store(p, dst, base); + } else { + i32 field_count = cast(i32)type->Struct.fields.count - 1; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ev(p, base, i); + field_src = lb_emit_ptr_offset(p, field_src, low); + lb_emit_store(p, field_dst, field_src); + } - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; + } else if (type->Struct.soa_kind == StructSoa_Dynamic) { + i32 field_count = cast(i32)type->Struct.fields.count - 3; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ev(p, base, i); + field_src = lb_emit_ptr_offset(p, field_src, low); + lb_emit_store(p, field_dst, field_src); } - lb_reset_copy_elision_hint(p, prev_hint); - } - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); } + + return dst; + #endif } break; - } - - case Type_SimdVector: { - if (cl->elems.count > 0) { - lbValue vector_value = lb_const_value(p->module, type, exact_value_compound(expr)); - defer (lb_addr_store(p, v, vector_value)); - - auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - - // NOTE(bill): Separate value, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); - } - - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } - - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } - - - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; - - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } - lb_reset_copy_elision_hint(p, prev_hint); - } + } + GB_PANIC("Unknown slicable type"); + case_end; - // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` - // might be a better option + 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)) { + 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); + return lb_addr_soa_variable(ptr, idx, nullptr); + } + lbValue addr = lb_build_expr(p, de->expr); + return lb_addr(addr); + case_end; - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - LLVMValueRef index = lb_const_int(p->module, t_u32, temp_data[i].elem_index).value; - vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, temp_data[i].value.value, index, ""); - } - } + case_ast_node(ce, CallExpr, expr); + BuiltinProcId builtin_id = BuiltinProc_Invalid; + if (ce->proc->tav.mode == Addressing_Builtin) { + Entity *e = entity_of_node(ce->proc); + if (e != nullptr) { + builtin_id = cast(BuiltinProcId)e->Builtin.id; + } else { + builtin_id = BuiltinProc_DIRECTIVE; } - break; } + auto const &tv = expr->tav; + if (builtin_id == BuiltinProc_swizzle && + is_type_array(tv.type)) { + // NOTE(bill, 2021-08-09): `swizzle` has some bizarre semantics so it needs to be + // specialized here for to be addressable + return lb_build_array_swizzle_addr(p, ce, tv); } + // NOTE(bill): This is make sure you never need to have an 'array_ev' + lbValue e = lb_build_expr(p, expr); + #if 1 + return lb_addr(lb_address_from_load_or_generate_local(p, e)); + #else + lbAddr v = lb_add_local_generated(p, e.type, false); + lb_addr_store(p, v, e); return v; + #endif + case_end; + + case_ast_node(cl, CompoundLit, expr); + return lb_build_addr_compound_lit(p, expr); case_end; case_ast_node(tc, TypeCast, expr); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index bcbd041ae..ee6980de4 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -175,7 +175,8 @@ struct lbLoopData { struct lbCompoundLitElemTempData { Ast * expr; lbValue value; - i32 elem_index; + i64 elem_index; + i64 elem_length; lbValue gep; }; -- cgit v1.2.3 From d2a362fd52bf3e750966fa120ef213a65c667cb1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 16:07:55 +0100 Subject: Clean up compound literal backend stuff some more --- src/llvm_backend_expr.cpp | 224 ++++++++++------------------------------------ 1 file changed, 48 insertions(+), 176 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 0cf2b3c03..f7ffe03f9 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3532,20 +3532,30 @@ void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice const &ele GB_ASSERT((hi-lo) > 0); - enum {MAX_ELEMENT_AMOUNT = 32}; - if ((hi-lo) <= MAX_ELEMENT_AMOUNT) { + if (bt->kind == Type_Matrix) { for (i64 k = lo; k < hi; k++) { lbCompoundLitElemTempData data = {}; data.value = value; - data.elem_index = k; + + data.elem_index = matrix_row_major_index_to_offset(bt, k); array_add(temp_data, data); } } else { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = lo; - data.elem_length = hi-lo; - array_add(temp_data, data); + enum {MAX_ELEMENT_AMOUNT = 32}; + if ((hi-lo) <= MAX_ELEMENT_AMOUNT) { + for (i64 k = lo; k < hi; k++) { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = k; + array_add(temp_data, data); + } + } else { + lbCompoundLitElemTempData data = {}; + data.value = value; + data.elem_index = lo; + data.elem_length = hi-lo; + array_add(temp_data, data); + } } } else { auto tav = fv->field->tav; @@ -3558,7 +3568,11 @@ void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice const &ele lbCompoundLitElemTempData data = {}; data.value = value; data.expr = fv->value; - data.elem_index = cast(i32)index; + if (bt->kind == Type_Matrix) { + data.elem_index = matrix_row_major_index_to_offset(bt, index); + } else { + data.elem_index = index; + } array_add(temp_data, data); } @@ -3574,25 +3588,29 @@ void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice const &ele lbCompoundLitElemTempData data = {}; data.value = ev; - data.elem_index = cast(i32)i; + if (bt->kind == Type_Matrix) { + data.elem_index = matrix_row_major_index_to_offset(bt, i); + } else { + data.elem_index = i; + } array_add(temp_data, data); } } } -void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array &temp_data) { +void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array const &temp_data) { for_array(i, temp_data) { auto td = temp_data[i]; if (td.value.value != nullptr) { if (td.elem_length > 0) { auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32); { - lbValue dst = temp_data[i].gep; + lbValue dst = td.gep; dst = lb_emit_ptr_offset(p, dst, loop_data.idx); - lb_emit_store(p, dst, temp_data[i].value); + lb_emit_store(p, dst, td.value); } lb_loop_end(p, loop_data); } else { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); + lb_emit_store(p, td.gep, td.value); } } } @@ -3907,93 +3925,14 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - // NOTE(bill): Separate value, gep, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); - - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, k); - array_add(&temp_data, data); - } - - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); - - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, index); - array_add(&temp_data, data); - } - - } else { - if (lb_is_elem_const(elem, et)) { - continue; - } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)matrix_row_major_index_to_offset(bt, i); - array_add(&temp_data, data); - } - } + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); + lbValue dst_ptr = lb_addr_get_ptr(p, v); for_array(i, temp_data) { - temp_data[i].gep = lb_emit_array_epi(p, lb_addr_get_ptr(p, v), temp_data[i].elem_index); + temp_data[i].gep = lb_emit_array_epi(p, dst_ptr, temp_data[i].elem_index); } - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; - - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } - - lb_reset_copy_elision_hint(p, prev_hint); - } - - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - lb_emit_store(p, temp_data[i].gep, temp_data[i].value); - } - } + lb_build_addr_compound_lit_assign_array(p, temp_data); } break; } @@ -4005,90 +3944,23 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { auto temp_data = array_make(temporary_allocator(), 0, cl->elems.count); - // NOTE(bill): Separate value, store into their own chunks - for_array(i, cl->elems) { - Ast *elem = cl->elems[i]; - if (elem->kind == Ast_FieldValue) { - ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { - continue; - } - if (is_ast_range(fv->field)) { - ast_node(ie, BinaryExpr, fv->field); - TypeAndValue lo_tav = ie->left->tav; - TypeAndValue hi_tav = ie->right->tav; - GB_ASSERT(lo_tav.mode == Addressing_Constant); - GB_ASSERT(hi_tav.mode == Addressing_Constant); - - TokenKind op = ie->op.kind; - i64 lo = exact_value_to_i64(lo_tav.value); - i64 hi = exact_value_to_i64(hi_tav.value); - if (op != Token_RangeHalf) { - hi += 1; - } - - lbValue value = lb_build_expr(p, fv->value); + lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type); - for (i64 k = lo; k < hi; k++) { - lbCompoundLitElemTempData data = {}; - data.value = value; - data.elem_index = cast(i32)k; - array_add(&temp_data, data); + // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` + // might be a better option + for_array(i, temp_data) { + auto td = temp_data[i]; + if (td.value.value != nullptr) { + if (td.elem_length > 0) { + for (i64 k = 0; k < td.elem_length; k++) { + LLVMValueRef index = lb_const_int(p->module, t_u32, td.elem_index + k).value; + vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); } - } else { - auto tav = fv->field->tav; - GB_ASSERT(tav.mode == Addressing_Constant); - i64 index = exact_value_to_i64(tav.value); + LLVMValueRef index = lb_const_int(p->module, t_u32, td.elem_index).value; + vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, td.value.value, index, ""); - lbValue value = lb_build_expr(p, fv->value); - lbCompoundLitElemTempData data = {}; - data.value = lb_emit_conv(p, value, et); - data.expr = fv->value; - data.elem_index = cast(i32)index; - array_add(&temp_data, data); - } - - } else { - if (lb_is_elem_const(elem, et)) { - continue; } - lbCompoundLitElemTempData data = {}; - data.expr = elem; - data.elem_index = cast(i32)i; - array_add(&temp_data, data); - } - } - - - for_array(i, temp_data) { - lbValue field_expr = temp_data[i].value; - Ast *expr = temp_data[i].expr; - - auto prev_hint = lb_set_copy_elision_hint(p, lb_addr(temp_data[i].gep), expr); - - if (field_expr.value == nullptr) { - field_expr = lb_build_expr(p, expr); - } - Type *t = field_expr.type; - GB_ASSERT(t->kind != Type_Tuple); - lbValue ev = lb_emit_conv(p, field_expr, et); - - if (!p->copy_elision_hint.used) { - temp_data[i].value = ev; - } - - lb_reset_copy_elision_hint(p, prev_hint); - } - - - // TODO(bill): reduce the need for individual `insertelement` if a `shufflevector` - // might be a better option - - for_array(i, temp_data) { - if (temp_data[i].value.value != nullptr) { - LLVMValueRef index = lb_const_int(p->module, t_u32, temp_data[i].elem_index).value; - vector_value.value = LLVMBuildInsertElement(p->builder, vector_value.value, temp_data[i].value.value, index, ""); } } } -- cgit v1.2.3 From a19494d3a789d43b7f2d2c3c79593bfef05a3876 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 11 Aug 2022 16:12:07 +0100 Subject: Minor refactoring of `lb_build_addr` --- src/llvm_backend_expr.cpp | 820 +++++++++++++++++++++++----------------------- 1 file changed, 417 insertions(+), 403 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index f7ffe03f9..5fd2fbe6f 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3616,6 +3616,421 @@ void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Arrayexpr)); + + bool deref = is_type_pointer(t); + t = base_type(type_deref(t)); + if (is_type_soa_struct(t)) { + // SOA STRUCTURES!!!! + lbValue val = lb_build_addr_ptr(p, ie->expr); + if (deref) { + val = lb_emit_load(p, val); + } + + lbValue index = lb_build_expr(p, ie->index); + return lb_addr_soa_variable(val, index, ie->index); + } + + if (ie->expr->tav.mode == Addressing_SoaVariable) { + // SOA Structures for slices/dynamic arrays + GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); + + lbValue field = lb_build_expr(p, ie->expr); + lbValue index = lb_build_expr(p, ie->index); + + + if (!build_context.no_bounds_check) { + // TODO HACK(bill): Clean up this hack to get the length for bounds checking + // GB_ASSERT(LLVMIsALoadInst(field.value)); + + // lbValue a = {}; + // a.value = LLVMGetOperand(field.value, 0); + // a.type = alloc_type_pointer(field.type); + + // irInstr *b = &a->Instr; + // GB_ASSERT(b->kind == irInstr_StructElementPtr); + // lbValue base_struct = b->StructElementPtr.address; + + // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct)))); + // lbValue len = ir_soa_struct_len(p, base_struct); + // lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + lbValue val = lb_emit_ptr_offset(p, field, index); + return lb_addr(val); + } + + GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr)); + + if (is_type_map(t)) { + lbAddr map_addr = lb_build_addr(p, ie->expr); + lbValue map_val = lb_addr_load(p, map_addr); + if (deref) { + map_val = lb_emit_load(p, map_val); + } + + lbValue key = lb_build_expr(p, ie->index); + key = lb_emit_conv(p, key, t->Map.key); + + Type *result_type = type_of_expr(expr); + lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val); + return lb_addr_map(map_ptr, key, t, result_type); + } + + switch (t->kind) { + case Type_Array: { + lbValue array = {}; + array = lb_build_addr_ptr(p, ie->expr); + if (deref) { + array = lb_emit_load(p, array); + } + lbValue index = lb_build_expr(p, ie->index); + index = lb_emit_conv(p, index, t_int); + lbValue elem = lb_emit_array_ep(p, array, index); + + auto index_tv = type_and_value_of_expr(ie->index); + if (index_tv.mode != Addressing_Constant) { + lbValue len = lb_const_int(p->module, t_int, t->Array.count); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + return lb_addr(elem); + } + + case Type_EnumeratedArray: { + lbValue array = {}; + array = lb_build_addr_ptr(p, ie->expr); + if (deref) { + array = lb_emit_load(p, array); + } + + Type *index_type = t->EnumeratedArray.index; + + auto index_tv = type_and_value_of_expr(ie->index); + + lbValue index = {}; + if (compare_exact_values(Token_NotEq, *t->EnumeratedArray.min_value, exact_value_i64(0))) { + if (index_tv.mode == Addressing_Constant) { + ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value); + index = lb_const_value(p->module, index_type, idx); + } else { + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type); + } + } else { + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + } + + lbValue elem = lb_emit_array_ep(p, array, index); + + if (index_tv.mode != Addressing_Constant) { + lbValue len = lb_const_int(p->module, t_int, t->EnumeratedArray.count); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + return lb_addr(elem); + } + + case Type_Slice: { + lbValue slice = {}; + slice = lb_build_expr(p, ie->expr); + if (deref) { + slice = lb_emit_load(p, slice); + } + lbValue elem = lb_slice_elem(p, slice); + lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lbValue len = lb_slice_len(p, slice); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + lbValue v = lb_emit_ptr_offset(p, elem, index); + return lb_addr(v); + } + + case Type_MultiPointer: { + lbValue multi_ptr = {}; + multi_ptr = lb_build_expr(p, ie->expr); + if (deref) { + multi_ptr = lb_emit_load(p, multi_ptr); + } + lbValue index = lb_build_expr(p, ie->index); + lbValue v = {}; + + LLVMValueRef indices[1] = {index.value}; + v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, t->MultiPointer.elem), multi_ptr.value, indices, 1, "foo"); + v.type = alloc_type_pointer(t->MultiPointer.elem); + return lb_addr(v); + } + + case Type_RelativeSlice: { + lbAddr slice_addr = {}; + if (deref) { + slice_addr = lb_addr(lb_build_expr(p, ie->expr)); + } else { + slice_addr = lb_build_addr(p, ie->expr); + } + lbValue slice = lb_addr_load(p, slice_addr); + + lbValue elem = lb_slice_elem(p, slice); + lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lbValue len = lb_slice_len(p, slice); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + lbValue v = lb_emit_ptr_offset(p, elem, index); + return lb_addr(v); + } + + case Type_DynamicArray: { + lbValue dynamic_array = {}; + dynamic_array = lb_build_expr(p, ie->expr); + if (deref) { + dynamic_array = lb_emit_load(p, dynamic_array); + } + lbValue elem = lb_dynamic_array_elem(p, dynamic_array); + lbValue len = lb_dynamic_array_len(p, dynamic_array); + lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + lbValue v = lb_emit_ptr_offset(p, elem, index); + return lb_addr(v); + } + + case Type_Matrix: { + lbValue matrix = {}; + matrix = lb_build_addr_ptr(p, ie->expr); + if (deref) { + matrix = lb_emit_load(p, matrix); + } + lbValue index = lb_build_expr(p, ie->index); + index = lb_emit_conv(p, index, t_int); + lbValue elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index); + elem = lb_emit_conv(p, elem, alloc_type_pointer(type_of_expr(expr))); + + auto index_tv = type_and_value_of_expr(ie->index); + if (index_tv.mode != Addressing_Constant) { + lbValue len = lb_const_int(p->module, t_int, t->Matrix.column_count); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + return lb_addr(elem); + } + + + case Type_Basic: { // Basic_string + lbValue str; + lbValue elem; + lbValue len; + lbValue index; + + str = lb_build_expr(p, ie->expr); + if (deref) { + str = lb_emit_load(p, str); + } + elem = lb_string_elem(p, str); + len = lb_string_len(p, str); + + index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + + return lb_addr(lb_emit_ptr_offset(p, elem, index)); + } + } + return {}; +} + + +lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { + ast_node(se, SliceExpr, expr); + + lbValue low = lb_const_int(p->module, t_int, 0); + lbValue high = {}; + + if (se->low != nullptr) { + low = lb_correct_endianness(p, lb_build_expr(p, se->low)); + } + if (se->high != nullptr) { + high = lb_correct_endianness(p, lb_build_expr(p, se->high)); + } + + bool no_indices = se->low == nullptr && se->high == nullptr; + + lbAddr addr = lb_build_addr(p, se->expr); + lbValue base = lb_addr_load(p, addr); + Type *type = base_type(base.type); + + if (is_type_pointer(type)) { + type = base_type(type_deref(type)); + addr = lb_addr(base); + base = lb_addr_load(p, addr); + } + + switch (type->kind) { + case Type_Slice: { + Type *slice_type = type; + lbValue len = lb_slice_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_slice_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } + + case Type_RelativeSlice: + GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the lb_addr_load"); + break; + + case Type_DynamicArray: { + Type *elem_type = type->DynamicArray.elem; + Type *slice_type = alloc_type_slice(elem_type); + + lbValue len = lb_dynamic_array_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } + + case Type_MultiPointer: { + lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false); + if (se->high == nullptr) { + lbValue offset = base; + LLVMValueRef indices[1] = {low.value}; + offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, ""); + lb_addr_store(p, res, offset); + } else { + low = lb_emit_conv(p, low, t_int); + high = lb_emit_conv(p, high, t_int); + + lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); + + LLVMValueRef indices[1] = {low.value}; + LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, ""); + LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, ""); + + LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value; + LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value; + LLVMBuildStore(p->builder, ptr, gep0); + LLVMBuildStore(p->builder, len, gep1); + } + return res; + } + + case Type_Array: { + Type *slice_type = alloc_type_slice(type->Array.elem); + lbValue len = lb_const_int(p->module, t_int, type->Array.count); + + if (high.value == nullptr) high = len; + + bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; + bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; + + if (!low_const || !high_const) { + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + } + lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr slice = lb_add_local_generated(p, slice_type, false); + lb_fill_slice(p, slice, elem, new_len); + return slice; + } + + case Type_Basic: { + GB_ASSERT(type == t_string); + lbValue len = lb_string_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr str = lb_add_local_generated(p, t_string, false); + lb_fill_string(p, str, elem, new_len); + return str; + } + + + case Type_Struct: + if (is_type_soa_struct(type)) { + lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr)); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + #if 1 + + lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true); + if (type->Struct.soa_kind == StructSoa_Fixed) { + i32 field_count = cast(i32)type->Struct.fields.count; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); + field_src = lb_emit_array_ep(p, field_src, low); + lb_emit_store(p, field_dst, field_src); + } + + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); + } else if (type->Struct.soa_kind == StructSoa_Slice) { + if (no_indices) { + lb_addr_store(p, dst, base); + } else { + i32 field_count = cast(i32)type->Struct.fields.count - 1; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ev(p, base, i); + field_src = lb_emit_ptr_offset(p, field_src, low); + lb_emit_store(p, field_dst, field_src); + } + + + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); + } + } else if (type->Struct.soa_kind == StructSoa_Dynamic) { + i32 field_count = cast(i32)type->Struct.fields.count - 3; + for (i32 i = 0; i < field_count; i++) { + lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); + lbValue field_src = lb_emit_struct_ev(p, base, i); + field_src = lb_emit_ptr_offset(p, field_src, low); + lb_emit_store(p, field_dst, field_src); + } + + + lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + lb_emit_store(p, len_dst, new_len); + } + + return dst; + #endif + } + break; + + } + + GB_PANIC("Unknown slicable type"); + return {}; +} + lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { ast_node(cl, CompoundLit, expr); @@ -4156,217 +4571,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_end; case_ast_node(ie, IndexExpr, expr); - Type *t = base_type(type_of_expr(ie->expr)); - - bool deref = is_type_pointer(t); - t = base_type(type_deref(t)); - if (is_type_soa_struct(t)) { - // SOA STRUCTURES!!!! - lbValue val = lb_build_addr_ptr(p, ie->expr); - if (deref) { - val = lb_emit_load(p, val); - } - - lbValue index = lb_build_expr(p, ie->index); - return lb_addr_soa_variable(val, index, ie->index); - } - - if (ie->expr->tav.mode == Addressing_SoaVariable) { - // SOA Structures for slices/dynamic arrays - GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); - - lbValue field = lb_build_expr(p, ie->expr); - lbValue index = lb_build_expr(p, ie->index); - - - if (!build_context.no_bounds_check) { - // TODO HACK(bill): Clean up this hack to get the length for bounds checking - // GB_ASSERT(LLVMIsALoadInst(field.value)); - - // lbValue a = {}; - // a.value = LLVMGetOperand(field.value, 0); - // a.type = alloc_type_pointer(field.type); - - // irInstr *b = &a->Instr; - // GB_ASSERT(b->kind == irInstr_StructElementPtr); - // lbValue base_struct = b->StructElementPtr.address; - - // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct)))); - // lbValue len = ir_soa_struct_len(p, base_struct); - // lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - lbValue val = lb_emit_ptr_offset(p, field, index); - return lb_addr(val); - } - - GB_ASSERT_MSG(is_type_indexable(t), "%s %s", type_to_string(t), expr_to_string(expr)); - - if (is_type_map(t)) { - lbAddr map_addr = lb_build_addr(p, ie->expr); - lbValue map_val = lb_addr_load(p, map_addr); - if (deref) { - map_val = lb_emit_load(p, map_val); - } - - lbValue key = lb_build_expr(p, ie->index); - key = lb_emit_conv(p, key, t->Map.key); - - Type *result_type = type_of_expr(expr); - lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val); - return lb_addr_map(map_ptr, key, t, result_type); - } - - switch (t->kind) { - case Type_Array: { - lbValue array = {}; - array = lb_build_addr_ptr(p, ie->expr); - if (deref) { - array = lb_emit_load(p, array); - } - lbValue index = lb_build_expr(p, ie->index); - index = lb_emit_conv(p, index, t_int); - lbValue elem = lb_emit_array_ep(p, array, index); - - auto index_tv = type_and_value_of_expr(ie->index); - if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->Array.count); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return lb_addr(elem); - } - - case Type_EnumeratedArray: { - lbValue array = {}; - array = lb_build_addr_ptr(p, ie->expr); - if (deref) { - array = lb_emit_load(p, array); - } - - Type *index_type = t->EnumeratedArray.index; - - auto index_tv = type_and_value_of_expr(ie->index); - - lbValue index = {}; - if (compare_exact_values(Token_NotEq, *t->EnumeratedArray.min_value, exact_value_i64(0))) { - if (index_tv.mode == Addressing_Constant) { - ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value); - index = lb_const_value(p->module, index_type, idx); - } else { - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type); - } - } else { - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - } - - lbValue elem = lb_emit_array_ep(p, array, index); - - if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->EnumeratedArray.count); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return lb_addr(elem); - } - - case Type_Slice: { - lbValue slice = {}; - slice = lb_build_expr(p, ie->expr); - if (deref) { - slice = lb_emit_load(p, slice); - } - lbValue elem = lb_slice_elem(p, slice); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lbValue len = lb_slice_len(p, slice); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); - } - - case Type_MultiPointer: { - lbValue multi_ptr = {}; - multi_ptr = lb_build_expr(p, ie->expr); - if (deref) { - multi_ptr = lb_emit_load(p, multi_ptr); - } - lbValue index = lb_build_expr(p, ie->index); - lbValue v = {}; - - LLVMValueRef indices[1] = {index.value}; - v.value = LLVMBuildGEP2(p->builder, lb_type(p->module, t->MultiPointer.elem), multi_ptr.value, indices, 1, "foo"); - v.type = alloc_type_pointer(t->MultiPointer.elem); - return lb_addr(v); - } - - case Type_RelativeSlice: { - lbAddr slice_addr = {}; - if (deref) { - slice_addr = lb_addr(lb_build_expr(p, ie->expr)); - } else { - slice_addr = lb_build_addr(p, ie->expr); - } - lbValue slice = lb_addr_load(p, slice_addr); - - lbValue elem = lb_slice_elem(p, slice); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lbValue len = lb_slice_len(p, slice); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); - } - - case Type_DynamicArray: { - lbValue dynamic_array = {}; - dynamic_array = lb_build_expr(p, ie->expr); - if (deref) { - dynamic_array = lb_emit_load(p, dynamic_array); - } - lbValue elem = lb_dynamic_array_elem(p, dynamic_array); - lbValue len = lb_dynamic_array_len(p, dynamic_array); - lbValue index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - lbValue v = lb_emit_ptr_offset(p, elem, index); - return lb_addr(v); - } - - case Type_Matrix: { - lbValue matrix = {}; - matrix = lb_build_addr_ptr(p, ie->expr); - if (deref) { - matrix = lb_emit_load(p, matrix); - } - lbValue index = lb_build_expr(p, ie->index); - index = lb_emit_conv(p, index, t_int); - lbValue elem = lb_emit_matrix_ep(p, matrix, lb_const_int(p->module, t_int, 0), index); - elem = lb_emit_conv(p, elem, alloc_type_pointer(type_of_expr(expr))); - - auto index_tv = type_and_value_of_expr(ie->index); - if (index_tv.mode != Addressing_Constant) { - lbValue len = lb_const_int(p->module, t_int, t->Matrix.column_count); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - } - return lb_addr(elem); - } - - - case Type_Basic: { // Basic_string - lbValue str; - lbValue elem; - lbValue len; - lbValue index; - - str = lb_build_expr(p, ie->expr); - if (deref) { - str = lb_emit_load(p, str); - } - elem = lb_string_elem(p, str); - len = lb_string_len(p, str); - - index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int); - lb_emit_bounds_check(p, ast_token(ie->index), index, len); - - return lb_addr(lb_emit_ptr_offset(p, elem, index)); - } - } + return lb_build_addr_index_expr(p, expr); case_end; case_ast_node(ie, MatrixIndexExpr, expr); @@ -4399,198 +4604,7 @@ lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { case_end; case_ast_node(se, SliceExpr, expr); - - lbValue low = lb_const_int(p->module, t_int, 0); - lbValue high = {}; - - if (se->low != nullptr) { - low = lb_correct_endianness(p, lb_build_expr(p, se->low)); - } - if (se->high != nullptr) { - high = lb_correct_endianness(p, lb_build_expr(p, se->high)); - } - - bool no_indices = se->low == nullptr && se->high == nullptr; - - lbAddr addr = lb_build_addr(p, se->expr); - lbValue base = lb_addr_load(p, addr); - Type *type = base_type(base.type); - - if (is_type_pointer(type)) { - type = base_type(type_deref(type)); - addr = lb_addr(base); - base = lb_addr_load(p, addr); - } - - switch (type->kind) { - case Type_Slice: { - Type *slice_type = type; - lbValue len = lb_slice_len(p, base); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - - lbValue elem = lb_emit_ptr_offset(p, lb_slice_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } - - case Type_RelativeSlice: - GB_PANIC("TODO(bill): Type_RelativeSlice should be handled above already on the lb_addr_load"); - break; - - case Type_DynamicArray: { - Type *elem_type = type->DynamicArray.elem; - Type *slice_type = alloc_type_slice(elem_type); - - lbValue len = lb_dynamic_array_len(p, base); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - - lbValue elem = lb_emit_ptr_offset(p, lb_dynamic_array_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } - - case Type_MultiPointer: { - lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false); - if (se->high == nullptr) { - lbValue offset = base; - LLVMValueRef indices[1] = {low.value}; - offset.value = LLVMBuildGEP2(p->builder, lb_type(p->module, offset.type->MultiPointer.elem), offset.value, indices, 1, ""); - lb_addr_store(p, res, offset); - } else { - low = lb_emit_conv(p, low, t_int); - high = lb_emit_conv(p, high, t_int); - - lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high); - - LLVMValueRef indices[1] = {low.value}; - LLVMValueRef ptr = LLVMBuildGEP2(p->builder, lb_type(p->module, base.type->MultiPointer.elem), base.value, indices, 1, ""); - LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, ""); - - LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value; - LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value; - LLVMBuildStore(p->builder, ptr, gep0); - LLVMBuildStore(p->builder, len, gep1); - } - return res; - } - - case Type_Array: { - Type *slice_type = alloc_type_slice(type->Array.elem); - lbValue len = lb_const_int(p->module, t_int, type->Array.count); - - if (high.value == nullptr) high = len; - - bool low_const = type_and_value_of_expr(se->low).mode == Addressing_Constant; - bool high_const = type_and_value_of_expr(se->high).mode == Addressing_Constant; - - if (!low_const || !high_const) { - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - } - lbValue elem = lb_emit_ptr_offset(p, lb_array_elem(p, lb_addr_get_ptr(p, addr)), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr slice = lb_add_local_generated(p, slice_type, false); - lb_fill_slice(p, slice, elem, new_len); - return slice; - } - - case Type_Basic: { - GB_ASSERT(type == t_string); - lbValue len = lb_string_len(p, base); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - - lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - - lbAddr str = lb_add_local_generated(p, t_string, false); - lb_fill_string(p, str, elem, new_len); - return str; - } - - - case Type_Struct: - if (is_type_soa_struct(type)) { - lbValue len = lb_soa_struct_len(p, lb_addr_get_ptr(p, addr)); - if (high.value == nullptr) high = len; - - if (!no_indices) { - lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); - } - #if 1 - - lbAddr dst = lb_add_local_generated(p, type_of_expr(expr), true); - if (type->Struct.soa_kind == StructSoa_Fixed) { - i32 field_count = cast(i32)type->Struct.fields.count; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); - field_src = lb_emit_array_ep(p, field_src, low); - lb_emit_store(p, field_dst, field_src); - } - - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); - } else if (type->Struct.soa_kind == StructSoa_Slice) { - if (no_indices) { - lb_addr_store(p, dst, base); - } else { - i32 field_count = cast(i32)type->Struct.fields.count - 1; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ev(p, base, i); - field_src = lb_emit_ptr_offset(p, field_src, low); - lb_emit_store(p, field_dst, field_src); - } - - - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); - } - } else if (type->Struct.soa_kind == StructSoa_Dynamic) { - i32 field_count = cast(i32)type->Struct.fields.count - 3; - for (i32 i = 0; i < field_count; i++) { - lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); - lbValue field_src = lb_emit_struct_ev(p, base, i); - field_src = lb_emit_ptr_offset(p, field_src, low); - lb_emit_store(p, field_dst, field_src); - } - - - lbValue len_dst = lb_emit_struct_ep(p, dst.addr, field_count); - lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); - lb_emit_store(p, len_dst, new_len); - } - - return dst; - #endif - } - break; - - } - - GB_PANIC("Unknown slicable type"); + return lb_build_addr_slice_expr(p, expr); case_end; case_ast_node(de, DerefExpr, expr); -- cgit v1.2.3 From 595efba747f791634f3dee67a7cbf466f86af988 Mon Sep 17 00:00:00 2001 From: Ian Lilley Date: Thu, 11 Aug 2022 11:43:19 -0400 Subject: removed unnecessary ternary --- src/llvm_backend_stmt.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 8f5120946..2aa9ba802 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -472,9 +472,9 @@ void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lbAddr value; if (val0_type != nullptr) { Entity *e = entity_of_node(rs->vals[0]); - value = lb_add_local(p, val0_type ? val0_type : lower.type, e, false); + value = lb_add_local(p, val0_type, e, false); } else { - value = lb_add_local_generated(p, val0_type ? val0_type : lower.type, false); + value = lb_add_local_generated(p, lower.type, false); } lb_addr_store(p, value, lower); -- cgit v1.2.3 From de8bd88d2a6f0e99af6fe76442bcccd159724872 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 12 Aug 2022 11:15:12 +0100 Subject: Clean up how procedures are typed in LLVM's dumb type system --- src/llvm_backend.cpp | 4 ++-- src/llvm_backend_general.cpp | 47 ++++++-------------------------------------- src/llvm_backend_proc.cpp | 22 +++++++++++++-------- 3 files changed, 22 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 6ee1541d6..6eec9103b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -739,11 +739,11 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start lb_begin_procedure_body(p); if (startup_type_info) { - LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, startup_type_info->type), startup_type_info->value, nullptr, 0, ""); + OdinLLVMBuildCall(p, {startup_type_info->value, startup_type_info->type}, nullptr, 0); } if (objc_names) { - LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, ""); + OdinLLVMBuildCall(p, {objc_names->value, objc_names->type}, nullptr, 0); } for_array(i, global_variables) { diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index ee6980de4..65cc8c41d 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -861,39 +861,6 @@ void lb_const_store(lbValue ptr, lbValue value) { LLVMSetInitializer(ptr.value, value.value); } - -bool lb_is_type_proc_recursive(Type *t) { - for (;;) { - if (t == nullptr) { - return false; - } - switch (t->kind) { - case Type_Named: - t = t->Named.base; - break; - case Type_Pointer: - t = t->Pointer.elem; - break; - case Type_Array: - t = t->Array.elem; - break; - case Type_EnumeratedArray: - t = t->EnumeratedArray.elem; - break; - case Type_Slice: - t = t->Slice.elem; - break; - case Type_DynamicArray: - t = t->DynamicArray.elem; - break; - case Type_Proc: - return true; - default: - return false; - } - } -} - void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { GB_ASSERT(value.value != nullptr); Type *a = type_deref(ptr.type); @@ -953,7 +920,7 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { } } - if (lb_is_type_proc_recursive(a)) { + if (is_type_proc(a)) { // NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be // stored as regular pointer with no procedure information @@ -1551,7 +1518,7 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) { if (e->flags & EntityFlag_ByPtr) { param_type = lb_type(m, alloc_type_pointer(e_type)); } else if (is_type_boolean(e_type) && - type_size_of(e_type) <= 1) { + type_size_of(e_type) <= 1) { param_type = LLVMInt1TypeInContext(m->ctx); } else { if (is_type_proc(e_type)) { @@ -2098,15 +2065,13 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } case Type_Proc: - // if (m->internal_type_level > 256) { // TODO HACK(bill): is this really enough? - if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough? - return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0); - } else { + { + // NOTE(bill): we do an explicit cast to the correct procedure type when calling the procedure LLVMTypeRef proc_raw_type = lb_type_internal_for_procedures_raw(m, type); - return LLVMPointerType(proc_raw_type, 0); + gb_unused(proc_raw_type); + return lb_type(m, t_rawptr); } - break; case Type_BitSet: { Type *ut = bit_set_to_int(type); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 392ff14c2..ade2a55cf 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1,6 +1,11 @@ +LLVMValueRef OdinLLVMBuildCall(lbProcedure *p, lbValue const &value, LLVMValueRef *args, unsigned arg_count) { + GB_ASSERT(is_type_proc(value.type)); + LLVMTypeRef type = lb_type_internal_for_procedures_raw(p->module, value.type); + LLVMValueRef func = LLVMBuildPointerCast(p->builder, value.value, LLVMPointerType(type, 0), ""); + return LLVMBuildCall2(p->builder, type, func, args, arg_count, ""); +} -LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count) -{ +LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count) { unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); GB_ASSERT_MSG(id != 0, "Unable to find %s", name); LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, type_count); @@ -740,6 +745,11 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, } for_array(i, processed_args) { lbValue arg = processed_args[i]; + if (is_type_proc(arg.type)) { + // NOTE(bill): all procedure types (function pointers) are typed as if they are `rawptr` + // and then the correct type is set at the call site + arg.value = LLVMBuildPointerCast(p->builder, arg.value, lb_type(p->module, arg.type), ""); + } args[arg_index++] = arg.value; } if (context_ptr.addr.value != nullptr) { @@ -752,11 +762,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, { LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, value.type); - LLVMTypeRef ftp = LLVMPointerType(fnp, 0); - LLVMValueRef fn = value.value; - if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) { - fn = LLVMBuildPointerCast(p->builder, fn, ftp, ""); - } + GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp)); { @@ -780,7 +786,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, } } - LLVMValueRef ret = LLVMBuildCall2(p->builder, fnp, fn, args, arg_count, ""); + LLVMValueRef ret = OdinLLVMBuildCall(p, value, args, arg_count); if (return_ptr.value != nullptr) { LLVMAddCallSiteAttribute(ret, 1, lb_create_enum_attribute_with_type(p->module->ctx, "sret", LLVMTypeOf(args[0]))); -- cgit v1.2.3 From 697c839c84b36b4e0c12ac9ea264e28f564ef5d5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 12 Aug 2022 12:29:11 +0100 Subject: Correct global constant procedure initialization --- src/llvm_backend.cpp | 12 ++++++++++++ src/llvm_backend_general.cpp | 7 ------- src/llvm_backend_type.cpp | 1 - 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 6eec9103b..7a8f57fdd 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -758,6 +758,10 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start GB_ASSERT(e->kind == Entity_Variable); e->code_gen_module = entity_module; + if (e->token.string == "XXH3_init_custom_secret") { + gb_printf_err("HERE1\n"); + } + Ast *init_expr = var->decl->init_expr; if (init_expr != nullptr) { lbValue init = lb_build_expr(p, init_expr); @@ -780,6 +784,10 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start var->init = init; } else if (lb_is_const_or_global(init)) { if (!var->is_initialized) { + if (is_type_proc(init.type)) { + LLVMTypeRef global_type = llvm_addr_type(p->module, var->var); + init.value = LLVMConstPointerCast(init.value, global_type); + } LLVMSetInitializer(var->var.value, init.value); var->is_initialized = true; continue; @@ -1649,6 +1657,10 @@ void lb_generate_code(lbGenerator *gen) { if (tav.value.kind != ExactValue_Invalid) { ExactValue v = tav.value; lbValue init = lb_const_value(m, tav.type, v); + if (is_type_proc(init.type)) { + LLVMTypeRef global_type = llvm_addr_type(m, var.var); + init.value = LLVMConstPointerCast(init.value, global_type); + } LLVMSetInitializer(g.value, init.value); var.is_initialized = true; } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 65cc8c41d..8458d8687 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -854,13 +854,6 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { lb_emit_store(p, addr.addr, value); } -void lb_const_store(lbValue ptr, lbValue value) { - GB_ASSERT(lb_is_const(ptr)); - GB_ASSERT(lb_is_const(value)); - GB_ASSERT(is_type_pointer(ptr.type)); - LLVMSetInitializer(ptr.value, value.value); -} - void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { GB_ASSERT(value.value != nullptr); Type *a = type_deref(ptr.type); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index d424fa5b2..c29713881 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -554,7 +554,6 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue index = lb_const_int(m, t_int, i); lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); - // TODO(bill): Make this constant if possible, 'lb_const_store' does not work lb_emit_store(p, type_info, lb_type_info(m, f->type)); if (f->token.string.len > 0) { lbValue name = lb_emit_ptr_offset(p, memory_names, index); -- cgit v1.2.3 From 22d16c20f8e446fb51d7faa14f22b9f86df8b393 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 12 Aug 2022 12:29:32 +0100 Subject: Remove debug message --- src/llvm_backend.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 7a8f57fdd..64b2ac5f3 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -758,10 +758,6 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start GB_ASSERT(e->kind == Entity_Variable); e->code_gen_module = entity_module; - if (e->token.string == "XXH3_init_custom_secret") { - gb_printf_err("HERE1\n"); - } - Ast *init_expr = var->decl->init_expr; if (init_expr != nullptr) { lbValue init = lb_build_expr(p, init_expr); -- cgit v1.2.3 From 8e7c7eeebabcf81e6ca06e44ae8b98554addd142 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 12 Aug 2022 13:48:10 +0100 Subject: Fix `lb_emit_ptr_offset` --- src/llvm_backend_proc.cpp | 10 +--------- src/llvm_backend_utility.cpp | 2 +- src/types.cpp | 7 ++++++- 3 files changed, 8 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ade2a55cf..784366476 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2077,15 +2077,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, lbValue ptr = lb_build_expr(p, ce->args[0]); lbValue len = lb_build_expr(p, ce->args[1]); len = lb_emit_conv(p, len, t_int); - - LLVMValueRef indices[1] = { - len.value, - }; - - lbValue res = {}; - res.type = tv.type; - res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, type_deref(tv.type)), ptr.value, indices, gb_count_of(indices), ""); - return res; + return lb_emit_ptr_offset(p, ptr, len); } case BuiltinProc_ptr_sub: { diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index ce7b43321..35e69a1be 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1285,7 +1285,7 @@ lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) { LLVMValueRef indices[1] = {index.value}; lbValue res = {}; res.type = ptr.type; - LLVMTypeRef type = lb_type(p->module, type_deref(ptr.type)); + LLVMTypeRef type = lb_type(p->module, type_deref(res.type, true)); if (lb_is_const(ptr) && lb_is_const(index)) { res.value = LLVMConstGEP2(type, ptr.value, indices, 1); diff --git a/src/types.cpp b/src/types.cpp index cba27fd6f..56b310867 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1115,7 +1115,7 @@ Type *alloc_type_simd_vector(i64 count, Type *elem, Type *generic_count=nullptr) //////////////////////////////////////////////////////////////// -Type *type_deref(Type *t) { +Type *type_deref(Type *t, bool allow_multi_pointer=false) { if (t != nullptr) { Type *bt = base_type(t); if (bt == nullptr) { @@ -1132,6 +1132,11 @@ Type *type_deref(Type *t) { GB_ASSERT(elem->kind == Type_Struct && elem->Struct.soa_kind != StructSoa_None); return elem->Struct.soa_elem; } + case Type_MultiPointer: + if (allow_multi_pointer) { + return bt->MultiPointer.elem; + } + break; } } return t; -- cgit v1.2.3 From f5431a046decd81ddb6eed7165368a44913eaca1 Mon Sep 17 00:00:00 2001 From: Ian Lilley Date: Mon, 15 Aug 2022 08:08:49 -0400 Subject: using correct type for val1 --- src/llvm_backend_stmt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 2aa9ba802..e55fae3a7 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -481,7 +481,7 @@ void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lbAddr index; if (val1_type != nullptr) { Entity *e = entity_of_node(rs->vals[1]); - index = lb_add_local(p, t_int, e, false); + index = lb_add_local(p, val1_type, e, false); } else { index = lb_add_local_generated(p, t_int, false); } -- cgit v1.2.3 From 2c004dbcc92684c484078727897e04b74f01b28c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Aug 2022 12:02:14 +0100 Subject: Improve `matrix` conversion rules --- src/check_expr.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 310874139..9c2d20781 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -818,6 +818,10 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type } if (is_type_matrix(dst)) { + if (are_types_identical(src, dst)) { + return 5; + } + Type *dst_elem = base_array_type(dst); i64 distance = check_distance_between_types(c, operand, dst_elem); if (distance >= 0) { -- cgit v1.2.3 From 5337b0b471edd40f062ab8cc3ff2deac469c164d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Aug 2022 16:16:36 +0100 Subject: Revert "Remove debug message" This reverts commit 22d16c20f8e446fb51d7faa14f22b9f86df8b393. Revert "Correct global constant procedure initialization" This reverts commit 697c839c84b36b4e0c12ac9ea264e28f564ef5d5. Revert "Clean up how procedures are typed in LLVM's dumb type system" This reverts commit de8bd88d2a6f0e99af6fe76442bcccd159724872. --- src/llvm_backend.cpp | 12 ++-------- src/llvm_backend_general.cpp | 54 +++++++++++++++++++++++++++++++++++++++----- src/llvm_backend_proc.cpp | 22 +++++++----------- src/llvm_backend_type.cpp | 1 + 4 files changed, 59 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 64b2ac5f3..6ee1541d6 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -739,11 +739,11 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start lb_begin_procedure_body(p); if (startup_type_info) { - OdinLLVMBuildCall(p, {startup_type_info->value, startup_type_info->type}, nullptr, 0); + LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, startup_type_info->type), startup_type_info->value, nullptr, 0, ""); } if (objc_names) { - OdinLLVMBuildCall(p, {objc_names->value, objc_names->type}, nullptr, 0); + LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, ""); } for_array(i, global_variables) { @@ -780,10 +780,6 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start var->init = init; } else if (lb_is_const_or_global(init)) { if (!var->is_initialized) { - if (is_type_proc(init.type)) { - LLVMTypeRef global_type = llvm_addr_type(p->module, var->var); - init.value = LLVMConstPointerCast(init.value, global_type); - } LLVMSetInitializer(var->var.value, init.value); var->is_initialized = true; continue; @@ -1653,10 +1649,6 @@ void lb_generate_code(lbGenerator *gen) { if (tav.value.kind != ExactValue_Invalid) { ExactValue v = tav.value; lbValue init = lb_const_value(m, tav.type, v); - if (is_type_proc(init.type)) { - LLVMTypeRef global_type = llvm_addr_type(m, var.var); - init.value = LLVMConstPointerCast(init.value, global_type); - } LLVMSetInitializer(g.value, init.value); var.is_initialized = true; } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 98bfb841a..071986458 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -854,6 +854,46 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { lb_emit_store(p, addr.addr, value); } +void lb_const_store(lbValue ptr, lbValue value) { + GB_ASSERT(lb_is_const(ptr)); + GB_ASSERT(lb_is_const(value)); + GB_ASSERT(is_type_pointer(ptr.type)); + LLVMSetInitializer(ptr.value, value.value); +} + + +bool lb_is_type_proc_recursive(Type *t) { + for (;;) { + if (t == nullptr) { + return false; + } + switch (t->kind) { + case Type_Named: + t = t->Named.base; + break; + case Type_Pointer: + t = t->Pointer.elem; + break; + case Type_Array: + t = t->Array.elem; + break; + case Type_EnumeratedArray: + t = t->EnumeratedArray.elem; + break; + case Type_Slice: + t = t->Slice.elem; + break; + case Type_DynamicArray: + t = t->DynamicArray.elem; + break; + case Type_Proc: + return true; + default: + return false; + } + } +} + void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { GB_ASSERT(value.value != nullptr); Type *a = type_deref(ptr.type); @@ -913,7 +953,7 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { } } - if (is_type_proc(a)) { + if (lb_is_type_proc_recursive(a)) { // NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be // stored as regular pointer with no procedure information @@ -1511,7 +1551,7 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) { if (e->flags & EntityFlag_ByPtr) { param_type = lb_type(m, alloc_type_pointer(e_type)); } else if (is_type_boolean(e_type) && - type_size_of(e_type) <= 1) { + type_size_of(e_type) <= 1) { param_type = LLVMInt1TypeInContext(m->ctx); } else { if (is_type_proc(e_type)) { @@ -2058,13 +2098,15 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } case Type_Proc: - { - // NOTE(bill): we do an explicit cast to the correct procedure type when calling the procedure + // if (m->internal_type_level > 256) { // TODO HACK(bill): is this really enough? + if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough? + return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0); + } else { LLVMTypeRef proc_raw_type = lb_type_internal_for_procedures_raw(m, type); - gb_unused(proc_raw_type); - return lb_type(m, t_rawptr); + return LLVMPointerType(proc_raw_type, 0); } + break; case Type_BitSet: { Type *ut = bit_set_to_int(type); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 784366476..bdb562884 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1,11 +1,6 @@ -LLVMValueRef OdinLLVMBuildCall(lbProcedure *p, lbValue const &value, LLVMValueRef *args, unsigned arg_count) { - GB_ASSERT(is_type_proc(value.type)); - LLVMTypeRef type = lb_type_internal_for_procedures_raw(p->module, value.type); - LLVMValueRef func = LLVMBuildPointerCast(p->builder, value.value, LLVMPointerType(type, 0), ""); - return LLVMBuildCall2(p->builder, type, func, args, arg_count, ""); -} -LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count) { +LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count) +{ unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); GB_ASSERT_MSG(id != 0, "Unable to find %s", name); LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, type_count); @@ -745,11 +740,6 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, } for_array(i, processed_args) { lbValue arg = processed_args[i]; - if (is_type_proc(arg.type)) { - // NOTE(bill): all procedure types (function pointers) are typed as if they are `rawptr` - // and then the correct type is set at the call site - arg.value = LLVMBuildPointerCast(p->builder, arg.value, lb_type(p->module, arg.type), ""); - } args[arg_index++] = arg.value; } if (context_ptr.addr.value != nullptr) { @@ -762,7 +752,11 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, { LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, value.type); - + LLVMTypeRef ftp = LLVMPointerType(fnp, 0); + LLVMValueRef fn = value.value; + if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) { + fn = LLVMBuildPointerCast(p->builder, fn, ftp, ""); + } GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp)); { @@ -786,7 +780,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, } } - LLVMValueRef ret = OdinLLVMBuildCall(p, value, args, arg_count); + LLVMValueRef ret = LLVMBuildCall2(p->builder, fnp, fn, args, arg_count, ""); if (return_ptr.value != nullptr) { LLVMAddCallSiteAttribute(ret, 1, lb_create_enum_attribute_with_type(p->module->ctx, "sret", LLVMTypeOf(args[0]))); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index c29713881..d424fa5b2 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -554,6 +554,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue index = lb_const_int(m, t_int, i); lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); + // TODO(bill): Make this constant if possible, 'lb_const_store' does not work lb_emit_store(p, type_info, lb_type_info(m, f->type)); if (f->token.string.len > 0) { lbValue name = lb_emit_ptr_offset(p, memory_names, index); -- cgit v1.2.3 From f2908cbc5aaec9c0472f1546f095eb4982a80232 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 16 Aug 2022 16:36:13 +0100 Subject: Remove debug crap with inlining --- src/llvm_backend_proc.cpp | 48 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index bdb562884..d7055ea31 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -148,34 +148,30 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) lb_add_attribute_to_proc(m, p->value, "noredzone"); } - if (build_context.optimization_level == 0 && build_context.ODIN_DEBUG) { + + switch (p->inlining) { + case ProcInlining_inline: + lb_add_attribute_to_proc(m, p->value, "alwaysinline"); + break; + case ProcInlining_no_inline: lb_add_attribute_to_proc(m, p->value, "noinline"); - lb_add_attribute_to_proc(m, p->value, "optnone"); - } else { - switch (p->inlining) { - case ProcInlining_inline: - lb_add_attribute_to_proc(m, p->value, "alwaysinline"); - break; - case ProcInlining_no_inline: - lb_add_attribute_to_proc(m, p->value, "noinline"); - break; - } + break; + } - switch (entity->Procedure.optimization_mode) { - case ProcedureOptimizationMode_None: - lb_add_attribute_to_proc(m, p->value, "optnone"); - break; - case ProcedureOptimizationMode_Minimal: - lb_add_attribute_to_proc(m, p->value, "optnone"); - break; - case ProcedureOptimizationMode_Size: - lb_add_attribute_to_proc(m, p->value, "optsize"); - break; - case ProcedureOptimizationMode_Speed: - // TODO(bill): handle this correctly - lb_add_attribute_to_proc(m, p->value, "optsize"); - break; - } + switch (entity->Procedure.optimization_mode) { + case ProcedureOptimizationMode_None: + lb_add_attribute_to_proc(m, p->value, "optnone"); + break; + case ProcedureOptimizationMode_Minimal: + lb_add_attribute_to_proc(m, p->value, "optnone"); + break; + case ProcedureOptimizationMode_Size: + lb_add_attribute_to_proc(m, p->value, "optsize"); + break; + case ProcedureOptimizationMode_Speed: + // TODO(bill): handle this correctly + lb_add_attribute_to_proc(m, p->value, "optsize"); + break; } if (!entity->Procedure.target_feature_disabled && -- cgit v1.2.3 From 5387ec5f299a9cb7ccf43a8c4f8b587f86bcb121 Mon Sep 17 00:00:00 2001 From: Jasper Geer Date: Tue, 16 Aug 2022 19:22:52 -0700 Subject: Remove erroneous byte swap --- src/llvm_backend_expr.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 5fd2fbe6f..322dcb7fd 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1777,9 +1777,6 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { lbValue res = {}; res = lb_emit_conv(p, value, platform_src_type); res = lb_emit_conv(p, res, platform_dst_type); - if (is_type_different_to_arch_endianness(dst)) { - res = lb_emit_byte_swap(p, res, platform_dst_type); - } return lb_emit_conv(p, res, t); } -- cgit v1.2.3 From 82e840a0ca3fb547ac93e680a3dcbbb67958077f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 17 Aug 2022 13:52:13 +0100 Subject: EXPERIMENTAL `intrinsics.valgrind_client_request` --- core/intrinsics/intrinsics.odin | 3 +++ src/build_settings.cpp | 3 +++ src/check_builtin.cpp | 35 +++++++++++++++++++++++++++++ src/checker.cpp | 3 +++ src/checker_builtin_procs.hpp | 4 ++++ src/llvm_backend_proc.cpp | 49 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+) (limited to 'src') diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 22b5d953d..0b682fbc3 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -295,6 +295,9 @@ objc_register_selector :: proc($name: string) -> objc_SEL --- objc_find_class :: proc($name: string) -> objc_Class --- objc_register_class :: proc($name: string) -> objc_Class --- + +valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2, a3, a4: uintptr) -> uintptr --- + // Internal compiler use only __entry_point :: proc() --- \ No newline at end of file diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d49f1cecf..9d5c3e556 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -228,6 +228,7 @@ struct BuildContext { bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing) bool ODIN_FOREIGN_ERROR_PROCEDURES; + bool ODIN_VALGRIND_SUPPORT; ErrorPosStyle ODIN_ERROR_POS_STYLE; @@ -1190,6 +1191,8 @@ void init_build_context(TargetMetrics *cross_target) { bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3); + bc->ODIN_VALGRIND_SUPPORT = is_arch_x86() && build_context.metrics.os != TargetOs_windows; + #undef LINK_FLAG_X64 #undef LINK_FLAG_386 } diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 687f1694b..83136d576 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5388,6 +5388,41 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } break; + case BuiltinProc_valgrind_client_request: + { + if (!is_arch_x86()) { + error(call, "'%.*s' is only allowed on x86 targets (i386, amd64)", LIT(builtin_name)); + return false; + } + + enum {ARG_COUNT = 7}; + GB_ASSERT(builtin_procs[BuiltinProc_valgrind_client_request].arg_count == ARG_COUNT); + + Operand operands[ARG_COUNT] = {}; + for (isize i = 0; i < ARG_COUNT; i++) { + Operand *op = &operands[i]; + check_expr_with_type_hint(c, op, ce->args[i], t_uintptr); + if (op->mode == Addressing_Invalid) { + return false; + } + convert_to_typed(c, op, t_uintptr); + if (op->mode == Addressing_Invalid) { + return false; + } + if (!are_types_identical(op->type, t_uintptr)) { + gbString str = type_to_string(op->type); + error(op->expr, "'%.*s' expected a uintptr, got %s", LIT(builtin_name), str); + gb_string_free(str); + return false; + } + } + + operand->type = t_uintptr; + operand->mode = Addressing_Value; + operand->value = {}; + return true; + } + } return true; diff --git a/src/checker.cpp b/src/checker.cpp index d01dc5323..a7470a4c9 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1037,6 +1037,9 @@ void init_universal(void) { add_global_bool_constant("ODIN_FOREIGN_ERROR_PROCEDURES", bc->ODIN_FOREIGN_ERROR_PROCEDURES); add_global_bool_constant("ODIN_DISALLOW_RTTI", bc->disallow_rtti); + add_global_bool_constant("ODIN_VALGRIND_SUPPORT", bc->ODIN_VALGRIND_SUPPORT); + + // Builtin Procedures for (isize i = 0; i < gb_count_of(builtin_procs); i++) { diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 8dd021255..717422df1 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -291,6 +291,8 @@ BuiltinProc__type_end, BuiltinProc_wasm_memory_atomic_wait32, BuiltinProc_wasm_memory_atomic_notify32, + BuiltinProc_valgrind_client_request, + BuiltinProc_COUNT, }; gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { @@ -582,4 +584,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("wasm_memory_size"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("wasm_memory_atomic_wait32"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("wasm_memory_atomic_notify32"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + + {STR_LIT("valgrind_client_request"), 7, false, Expr_Expr, BuiltinProcPkg_intrinsics}, }; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index d7055ea31..f85d8397c 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2745,6 +2745,55 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, res.value = LLVMBuildCall2(p->builder, func_type, the_asm, args, gb_count_of(args), ""); return res; } + + case BuiltinProc_valgrind_client_request: + { + lbValue args[7] = {}; + for (isize i = 0; i < 7; i++) { + args[i] = lb_emit_conv(p, lb_build_expr(p, ce->args[i]), t_uintptr); + } + if (!build_context.ODIN_VALGRIND_SUPPORT) { + return args[0]; + } + lbValue array = lb_generate_local_array(p, t_uintptr, 6, false); + for (isize i = 0; i < 6; i++) { + lbValue gep = lb_emit_array_epi(p, array, i); + lb_emit_store(p, gep, args[i+1]); + } + + switch (build_context.metrics.arch) { + case TargetArch_amd64: + { + Type *param_types[2] = {}; + param_types[0] = t_uintptr; + param_types[1] = array.type; + + Type *type = alloc_type_proc_from_types(param_types, gb_count_of(param_types), t_uintptr, false, ProcCC_None); + LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type); + LLVMValueRef the_asm = llvm_get_inline_asm( + func_type, + str_lit("rolq $3, %rdi; rolq $13, %rdi\n rolq $61, %rdi; rolq $51, %rdi\n xchgq %rbx, %rbx"), + str_lit("={rdx},{rdx},{rax},cc,memory"), + true + ); + + LLVMValueRef asm_args[2] = {}; + asm_args[0] = args[0].value; + asm_args[1] = array.value; + + lbValue res = {}; + res.type = t_uintptr; + res.value = LLVMBuildCall2(p->builder, func_type, the_asm, asm_args, gb_count_of(asm_args), ""); + return res; + } + break; + default: + GB_PANIC("Unsupported architecture: %.*s", LIT(target_arch_names[build_context.metrics.arch])); + break; + } + + } + } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); -- cgit v1.2.3 From f504b200a9ccee250032e6ed2c1dd3d40e9c9acb Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 17 Aug 2022 15:54:45 +0100 Subject: Improve `unreachable` generation by putting a `trap` before it --- src/llvm_backend_utility.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 8be339ca7..480bad75c 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -42,6 +42,7 @@ bool lb_is_type_aggregate(Type *t) { void lb_emit_unreachable(lbProcedure *p) { LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); if (instr == nullptr || !lb_is_instr_terminating(instr)) { + lb_call_intrinsic(p, "trap", nullptr, 0, nullptr, 0); LLVMBuildUnreachable(p->builder); } } -- cgit v1.2.3 From 6e9f9e6f3c5af4745907dfd86c44687355dcc84e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 17 Aug 2022 15:57:56 +0100 Subject: Fix typo --- src/llvm_backend_utility.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 480bad75c..7163f1d9e 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -42,7 +42,7 @@ bool lb_is_type_aggregate(Type *t) { void lb_emit_unreachable(lbProcedure *p) { LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); if (instr == nullptr || !lb_is_instr_terminating(instr)) { - lb_call_intrinsic(p, "trap", nullptr, 0, nullptr, 0); + lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0); LLVMBuildUnreachable(p->builder); } } -- cgit v1.2.3 From c8c076f970448ff25a3489fdaeb91c742bead8f8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 19 Aug 2022 16:57:36 +0100 Subject: Fix #1963 --- src/llvm_backend_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 5fd2fbe6f..3b2e6c29f 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3577,7 +3577,7 @@ void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice const &ele } } else { - if (lb_is_elem_const(elem, et)) { + if (bt->kind != Type_DynamicArray && lb_is_elem_const(elem, et)) { continue; } -- cgit v1.2.3 From b70d211f21f5d43e2151008cdc645c9ffb7175aa Mon Sep 17 00:00:00 2001 From: Jeroen Ruigrok van der Werven Date: Mon, 22 Aug 2022 11:15:53 +0200 Subject: fix: Expand OpenBSD include for wait.h to all Unix closes: #1968 --- src/gb/gb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/gb/gb.h b/src/gb/gb.h index d09c7618b..90f2fd15a 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -90,7 +90,7 @@ extern "C" { #error This operating system is not supported #endif -#if defined(GB_SYSTEM_OPENBSD) +#if defined(GB_SYSTEM_UNIX) #include #endif -- cgit v1.2.3 From 2908923db9d047185de110991cc3347a112c38a6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Aug 2022 12:18:42 +0100 Subject: Fix #1972 --- core/slice/slice.odin | 4 ++-- core/sys/unix/syscalls_linux.odin | 4 ++-- src/check_builtin.cpp | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/core/slice/slice.odin b/core/slice/slice.odin index 440cf643f..e76a5599d 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -14,14 +14,14 @@ _ :: mem Turn a pointer and a length into a slice. */ from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T { - return ([^]T)(ptr)[:count] + return ([^]T)(ptr)[:count] } /* Turn a pointer and a length into a byte slice. */ bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte { - return ([^]byte)(ptr)[:byte_count] + return ([^]byte)(ptr)[:byte_count] } /* diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index d611e33f0..48e9b49ab 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1568,7 +1568,7 @@ sys_gettid :: proc "contextless" () -> int { } sys_getrandom :: proc "contextless" (buf: [^]byte, buflen: int, flags: uint) -> int { - return cast(int)intrinsics.syscall(SYS_getrandom, buf, cast(uintptr)(buflen), cast(uintptr)(flags)) + return cast(int)intrinsics.syscall(SYS_getrandom, uintptr(buf), uintptr(buflen), uintptr(flags)) } sys_open :: proc "contextless" (path: cstring, flags: int, mode: int = 0o000) -> int { @@ -1748,7 +1748,7 @@ sys_unlink :: proc "contextless" (path: cstring) -> int { } sys_unlinkat :: proc "contextless" (dfd: int, path: cstring, flag: int = 0) -> int { - return int(intrinsics.syscall(SYS_unlinkat, uintptr(dfd), uintptr(rawptr(path)), flag)) + return int(intrinsics.syscall(SYS_unlinkat, uintptr(dfd), uintptr(rawptr(path)), uintptr(flag))) } sys_rmdir :: proc "contextless" (path: cstring) -> int { diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 83136d576..e55a2e024 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4523,7 +4523,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 if (x.mode != Addressing_Invalid) { convert_to_typed(c, &x, t_uintptr); } - if (!is_type_uintptr(operand->type)) { + convert_to_typed(c, &x, t_uintptr); + if (!is_type_uintptr(x.type)) { gbString t = type_to_string(x.type); error(x.expr, "Argument %td must be of type 'uintptr', got %s", i, t); gb_string_free(t); -- cgit v1.2.3 From f1ffd902944df5a7a8f89ca9a3d18e3c94307348 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Aug 2022 12:52:57 +0100 Subject: Fix #1966 --- src/types.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/types.cpp b/src/types.cpp index 0ca239bde..570d7c556 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3571,10 +3571,22 @@ i64 type_align_of_internal(Type *t, TypePath *path) { return build_context.word_size; } - // return gb_clamp(next_pow2(type_size_of(t)), 1, build_context.max_align); + i64 max_alignment = build_context.word_size; + if (is_arch_wasm()) { + // NOTE(bill): wasm32 with LLVM defines its default datalayout as: + // + // e-m:e-p:32:32-i64:64-n32:64-S128 + // + // This means that the alignment of a 64-bit type is 64-bits and not 32-bits like + // on other 32-bit architectures + // + // See: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md + max_alignment = 8; + } + // NOTE(bill): Things that are bigger than build_context.word_size, are actually comprised of smaller types // TODO(bill): Is this correct for 128-bit types (integers)? - return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.word_size); + return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, max_alignment); } i64 *type_set_offsets_of(Slice const &fields, bool is_packed, bool is_raw_union) { -- cgit v1.2.3 From 4ba486baa2d1414393dff0d7ddaff777f4592cbd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Aug 2022 12:58:16 +0100 Subject: Add extra max alignment parameter for metrics (specifically for SIMD) --- src/build_settings.cpp | 81 ++++++++++++++++++-------------------------------- src/types.cpp | 17 ++--------- 2 files changed, 31 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 9d5c3e556..3ad4dd3e3 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -116,6 +116,7 @@ struct TargetMetrics { TargetArchKind arch; isize word_size; isize max_align; + isize max_simd_align; String target_triplet; String target_data_layout; TargetABIKind abi; @@ -235,8 +236,9 @@ struct BuildContext { TargetEndianKind endian_kind; // In bytes - i64 word_size; // Size of a pointer, must be >= 4 - i64 max_align; // max alignment, must be >= 1 (and typically >= word_size) + i64 word_size; // Size of a pointer, must be >= 4 + i64 max_align; // max alignment, must be >= 1 (and typically >= word_size) + i64 max_simd_align; // max alignment, must be >= 1 (and typically >= word_size) CommandKind command_kind; String command; @@ -339,15 +341,13 @@ bool global_ignore_warnings(void) { gb_global TargetMetrics target_windows_i386 = { TargetOs_windows, TargetArch_i386, - 4, - 8, + 4, 4, 8, str_lit("i386-pc-windows-msvc"), }; gb_global TargetMetrics target_windows_amd64 = { TargetOs_windows, TargetArch_amd64, - 8, - 16, + 8, 8, 16, str_lit("x86_64-pc-windows-msvc"), str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), }; @@ -355,24 +355,21 @@ gb_global TargetMetrics target_windows_amd64 = { gb_global TargetMetrics target_linux_i386 = { TargetOs_linux, TargetArch_i386, - 4, - 8, + 4, 4, 8, str_lit("i386-pc-linux-gnu"), }; gb_global TargetMetrics target_linux_amd64 = { TargetOs_linux, TargetArch_amd64, - 8, - 16, + 8, 8, 16, str_lit("x86_64-pc-linux-gnu"), str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), }; gb_global TargetMetrics target_linux_arm64 = { TargetOs_linux, TargetArch_arm64, - 8, - 16, + 8, 8, 16, str_lit("aarch64-linux-elf"), str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"), }; @@ -380,8 +377,7 @@ gb_global TargetMetrics target_linux_arm64 = { gb_global TargetMetrics target_linux_arm32 = { TargetOs_linux, TargetArch_arm32, - 4, - 8, + 4, 4, 8, str_lit("arm-linux-gnu"), str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"), }; @@ -389,8 +385,7 @@ gb_global TargetMetrics target_linux_arm32 = { gb_global TargetMetrics target_darwin_amd64 = { TargetOs_darwin, TargetArch_amd64, - 8, - 16, + 8, 8, 16, str_lit("x86_64-apple-darwin"), str_lit("e-m:o-i64:64-f80:128-n8:16:32:64-S128"), }; @@ -398,8 +393,7 @@ gb_global TargetMetrics target_darwin_amd64 = { gb_global TargetMetrics target_darwin_arm64 = { TargetOs_darwin, TargetArch_arm64, - 8, - 16, + 8, 8, 16, str_lit("arm64-apple-macosx11.0.0"), str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct? }; @@ -407,16 +401,14 @@ gb_global TargetMetrics target_darwin_arm64 = { gb_global TargetMetrics target_freebsd_i386 = { TargetOs_freebsd, TargetArch_i386, - 4, - 8, + 4, 4, 8, str_lit("i386-unknown-freebsd-elf"), }; gb_global TargetMetrics target_freebsd_amd64 = { TargetOs_freebsd, TargetArch_amd64, - 8, - 16, + 8, 8, 16, str_lit("x86_64-unknown-freebsd-elf"), str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), }; @@ -424,8 +416,7 @@ gb_global TargetMetrics target_freebsd_amd64 = { gb_global TargetMetrics target_openbsd_amd64 = { TargetOs_openbsd, TargetArch_amd64, - 8, - 16, + 8, 8, 16, str_lit("x86_64-unknown-openbsd-elf"), str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"), }; @@ -433,16 +424,14 @@ gb_global TargetMetrics target_openbsd_amd64 = { gb_global TargetMetrics target_essence_amd64 = { TargetOs_essence, TargetArch_amd64, - 8, - 16, + 8, 8, 16, str_lit("x86_64-pc-none-elf"), }; gb_global TargetMetrics target_freestanding_wasm32 = { TargetOs_freestanding, TargetArch_wasm32, - 4, - 8, + 4, 8, 16, str_lit("wasm32-freestanding-js"), str_lit(""), }; @@ -450,8 +439,7 @@ gb_global TargetMetrics target_freestanding_wasm32 = { gb_global TargetMetrics target_js_wasm32 = { TargetOs_js, TargetArch_wasm32, - 4, - 8, + 4, 8, 16, str_lit("wasm32-js-js"), str_lit(""), }; @@ -459,8 +447,7 @@ gb_global TargetMetrics target_js_wasm32 = { gb_global TargetMetrics target_js_wasm64 = { TargetOs_js, TargetArch_wasm64, - 8, - 16, + 8, 8, 16, str_lit("wasm64-js-js"), str_lit(""), }; @@ -468,27 +455,15 @@ gb_global TargetMetrics target_js_wasm64 = { gb_global TargetMetrics target_wasi_wasm32 = { TargetOs_wasi, TargetArch_wasm32, - 4, - 8, + 4, 8, 16, str_lit("wasm32-wasi-js"), str_lit(""), }; - -// gb_global TargetMetrics target_freestanding_wasm64 = { -// TargetOs_freestanding, -// TargetArch_wasm64, -// 8, -// 16, -// str_lit("wasm64-freestanding-js"), -// str_lit(""), -// }; - gb_global TargetMetrics target_freestanding_amd64_sysv = { TargetOs_freestanding, TargetArch_amd64, - 8, - 16, + 8, 8, 16, str_lit("x86_64-pc-none-gnu"), str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"), TargetABI_SysV, @@ -517,7 +492,7 @@ gb_global NamedTargetMetrics named_targets[] = { { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 }, { str_lit("wasi_wasm32"), &target_wasi_wasm32 }, { str_lit("js_wasm32"), &target_js_wasm32 }, - { str_lit("js_wasm64"), &target_js_wasm64 }, + // { str_lit("js_wasm64"), &target_js_wasm64 }, { str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv }, }; @@ -1084,14 +1059,16 @@ void init_build_context(TargetMetrics *cross_target) { GB_ASSERT(metrics->arch != TargetArch_Invalid); GB_ASSERT(metrics->word_size > 1); GB_ASSERT(metrics->max_align > 1); + GB_ASSERT(metrics->max_simd_align > 1); bc->metrics = *metrics; - bc->ODIN_OS = target_os_names[metrics->os]; - bc->ODIN_ARCH = target_arch_names[metrics->arch]; - bc->endian_kind = target_endians[metrics->arch]; - bc->word_size = metrics->word_size; - bc->max_align = metrics->max_align; + bc->ODIN_OS = target_os_names[metrics->os]; + bc->ODIN_ARCH = target_arch_names[metrics->arch]; + bc->endian_kind = target_endians[metrics->arch]; + bc->word_size = metrics->word_size; + bc->max_align = metrics->max_align; + bc->max_simd_align = metrics->max_simd_align; bc->link_flags = str_lit(" "); #if defined(DEFAULT_TO_THREADED_CHECKER) diff --git a/src/types.cpp b/src/types.cpp index 570d7c556..aa4a3c4a1 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3556,7 +3556,7 @@ i64 type_align_of_internal(Type *t, TypePath *path) { case Type_SimdVector: { // IMPORTANT TODO(bill): Figure out the alignment of vector types - return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align*2); + return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_simd_align*2); } case Type_Matrix: @@ -3571,22 +3571,9 @@ i64 type_align_of_internal(Type *t, TypePath *path) { return build_context.word_size; } - i64 max_alignment = build_context.word_size; - if (is_arch_wasm()) { - // NOTE(bill): wasm32 with LLVM defines its default datalayout as: - // - // e-m:e-p:32:32-i64:64-n32:64-S128 - // - // This means that the alignment of a 64-bit type is 64-bits and not 32-bits like - // on other 32-bit architectures - // - // See: https://github.com/WebAssembly/tool-conventions/blob/main/BasicCABI.md - max_alignment = 8; - } - // NOTE(bill): Things that are bigger than build_context.word_size, are actually comprised of smaller types // TODO(bill): Is this correct for 128-bit types (integers)? - return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, max_alignment); + return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align); } i64 *type_set_offsets_of(Slice const &fields, bool is_packed, bool is_raw_union) { -- cgit v1.2.3 From aeacf3a9d8a1f6aa36d5c1315e1d8529bb985847 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Aug 2022 13:07:41 +0100 Subject: Correct max alignment handling throughout the llvm backend --- src/build_settings.cpp | 22 ++++++++++++---------- src/llvm_abi.cpp | 2 +- src/llvm_backend_expr.cpp | 6 +++--- src/llvm_backend_general.cpp | 5 ++++- src/llvm_backend_stmt.cpp | 2 +- src/types.cpp | 2 +- 6 files changed, 22 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 3ad4dd3e3..3f6be3c48 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -428,12 +428,13 @@ gb_global TargetMetrics target_essence_amd64 = { str_lit("x86_64-pc-none-elf"), }; + gb_global TargetMetrics target_freestanding_wasm32 = { TargetOs_freestanding, TargetArch_wasm32, 4, 8, 16, str_lit("wasm32-freestanding-js"), - str_lit(""), + str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"), }; gb_global TargetMetrics target_js_wasm32 = { @@ -441,15 +442,7 @@ gb_global TargetMetrics target_js_wasm32 = { TargetArch_wasm32, 4, 8, 16, str_lit("wasm32-js-js"), - str_lit(""), -}; - -gb_global TargetMetrics target_js_wasm64 = { - TargetOs_js, - TargetArch_wasm64, - 8, 8, 16, - str_lit("wasm64-js-js"), - str_lit(""), + str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"), }; gb_global TargetMetrics target_wasi_wasm32 = { @@ -457,6 +450,15 @@ gb_global TargetMetrics target_wasi_wasm32 = { TargetArch_wasm32, 4, 8, 16, str_lit("wasm32-wasi-js"), + str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"), +}; + + +gb_global TargetMetrics target_js_wasm64 = { + TargetOs_js, + TargetArch_wasm64, + 8, 8, 16, + str_lit("wasm64-js-js"), str_lit(""), }; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 2ee8dc673..4bdc31077 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -294,7 +294,7 @@ i64 lb_alignof(LLVMTypeRef type) { i64 elem_size = lb_sizeof(elem); i64 count = LLVMGetVectorSize(type); i64 size = count * elem_size; - return gb_clamp(next_pow2(size), 1, build_context.max_align); + return gb_clamp(next_pow2(size), 1, build_context.max_simd_align); } } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index dd66943d7..7d81d1407 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -137,7 +137,7 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type) lbAddr res_addr = lb_add_local(p, type, nullptr, false, 0, true); lbValue res = lb_addr_get_ptr(p, res_addr); - bool inline_array_arith = type_size_of(type) <= build_context.max_align; + bool inline_array_arith = lb_can_try_to_inline_array_arith(type); i32 count = cast(i32)get_array_type_count(tl); @@ -436,7 +436,7 @@ lbValue lb_emit_arith_array(lbProcedure *p, TokenKind op, lbValue lhs, lbValue r return direct_vector_res; } - bool inline_array_arith = type_size_of(type) <= build_context.max_align; + bool inline_array_arith = lb_can_try_to_inline_array_arith(type); if (inline_array_arith) { auto dst_ptrs = slice_make(temporary_allocator(), n); @@ -2303,7 +2303,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri cmp_op = Token_And; } - bool inline_array_arith = type_size_of(tl) <= build_context.max_align; + bool inline_array_arith = lb_can_try_to_inline_array_arith(tl); i32 count = 0; switch (tl->kind) { case Type_Array: count = cast(i32)tl->Array.count; break; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 071986458..6f98458fa 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -591,6 +591,9 @@ bool lb_try_update_alignment(lbValue ptr, unsigned alignment) { return lb_try_update_alignment(ptr.value, alignment); } +bool lb_can_try_to_inline_array_arith(Type *t) { + return type_size_of(t) <= build_context.max_simd_align; +} bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vector_type_) { Type *array_type = base_type(type_deref(ptr.type)); @@ -599,7 +602,7 @@ bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vector_type_) { Type *elem_type = base_array_type(array_type); // TODO(bill): Determine what is the correct limit for doing vector arithmetic - if (type_size_of(array_type) <= build_context.max_align && + if (lb_can_try_to_inline_array_arith(array_type) && is_type_valid_vector_elem(elem_type)) { // Try to treat it like a vector if possible bool possible = false; diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index e55fae3a7..175c4c537 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1796,7 +1796,7 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue rhs = lb_emit_conv(p, value, lhs_type); - bool inline_array_arith = type_size_of(array_type) <= build_context.max_align; + bool inline_array_arith = lb_can_try_to_inline_array_arith(array_type); if (lhs.kind == lbAddr_Swizzle) { diff --git a/src/types.cpp b/src/types.cpp index aa4a3c4a1..b7cb4dd2c 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1428,7 +1428,7 @@ i64 matrix_align_of(Type *t, struct TypePath *tp) { } GB_ASSERT(min_alignment >= elem_align); - i64 align = gb_min(min_alignment, build_context.max_align); + i64 align = gb_min(min_alignment, build_context.max_simd_align); return align; } -- cgit v1.2.3 From d56789e5a77e597ec09d7ffed46ba65543d25750 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Aug 2022 15:58:20 +0100 Subject: Add very basic escape analysis on `return` values --- src/check_stmt.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 451325324..5673206f3 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1396,6 +1396,22 @@ bool check_stmt_internal_builtin_proc_id(Ast *expr, BuiltinProcId *id_) { return id != BuiltinProc_Invalid; } +bool check_expr_is_stack_variable(Ast *expr) { + Entity *e = entity_of_node(expr); + if (e && e->kind == Entity_Variable) { + if (e->flags & EntityFlag_Static) { + // okay + } else if (e->Variable.thread_local_model.len != 0) { + // okay + } else if (e->scope) { + if ((e->scope->flags & (ScopeFlag_Global|ScopeFlag_File)) == 0) { + return true; + } + } + } + return false; +} + void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { u32 mod_flags = flags & (~Stmt_FallthroughAllowed); switch (node->kind) { @@ -1678,6 +1694,29 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { if (is_type_untyped(o->type)) { update_untyped_expr_type(ctx, o->expr, e->type, true); } + + + // NOTE(bill): This is very basic escape analysis + // This needs to be improved tremendously, and a lot of it done during the + // middle-end (or LLVM side) to improve checks and error messages + Ast *expr = unparen_expr(o->expr); + if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) { + Ast *x = unparen_expr(expr->UnaryExpr.expr); + if (x->kind == Ast_CompoundLit) { + error(expr, "Cannot return the address to a stack value from a procedure"); + } else if (x->kind == Ast_IndexExpr) { + Ast *array = x->IndexExpr.expr; + if (is_type_array_like(type_of_expr(array)) && check_expr_is_stack_variable(array)) { + gbString t = type_to_string(type_of_expr(array)); + error(expr, "Cannot return the address to an element of stack variable from a procedure, of type %s", t); + gb_string_free(t); + } + } else { + if (check_expr_is_stack_variable(x)) { + error(expr, "Cannot return the address to a stack variable from a procedure"); + } + } + } } } case_end; -- cgit v1.2.3 From af1b3b6368ffe690ba7f395920fd658b575fa042 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Aug 2022 16:03:04 +0100 Subject: Correct `check_expr_is_stack_variable` --- src/check_stmt.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 5673206f3..133ca581f 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1397,6 +1397,7 @@ bool check_stmt_internal_builtin_proc_id(Ast *expr, BuiltinProcId *id_) { } bool check_expr_is_stack_variable(Ast *expr) { + expr = unparen_expr(expr); Entity *e = entity_of_node(expr); if (e && e->kind == Entity_Variable) { if (e->flags & EntityFlag_Static) { @@ -1404,7 +1405,7 @@ bool check_expr_is_stack_variable(Ast *expr) { } else if (e->Variable.thread_local_model.len != 0) { // okay } else if (e->scope) { - if ((e->scope->flags & (ScopeFlag_Global|ScopeFlag_File)) == 0) { + if ((e->scope->flags & (ScopeFlag_Global|ScopeFlag_File|ScopeFlag_Type)) == 0) { return true; } } -- cgit v1.2.3 From 776927709bbf274a8c7d63dcff250726a90cf3a3 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 26 Aug 2022 12:11:27 +0100 Subject: Check for `using` variables --- src/check_stmt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 133ca581f..884c7b5ae 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1400,7 +1400,7 @@ bool check_expr_is_stack_variable(Ast *expr) { expr = unparen_expr(expr); Entity *e = entity_of_node(expr); if (e && e->kind == Entity_Variable) { - if (e->flags & EntityFlag_Static) { + if (e->flags & (EntityFlag_Static|EntityFlag_Using)) { // okay } else if (e->Variable.thread_local_model.len != 0) { // okay -- cgit v1.2.3 From 8fd5bef0bd3dd149219acb866b717f80dd7b8061 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 26 Aug 2022 12:14:04 +0100 Subject: Fix #1977 --- src/check_stmt.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 884c7b5ae..d741ceabf 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1464,6 +1464,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { AstSelectorCallExpr *se = &expr->SelectorCallExpr; ast_node(ce, CallExpr, se->call); Type *t = base_type(type_of_expr(ce->proc)); + if (t == nullptr) { + gbString expr_str = expr_to_string(ce->proc); + error(node, "'%s' is not a value field nor procedure", expr_str); + gb_string_free(expr_str); + return; + } if (t->kind == Type_Proc) { do_require = t->Proc.require_results; } else if (check_stmt_internal_builtin_proc_id(ce->proc, &builtin_id)) { -- cgit v1.2.3