From 4d06a54c0ce7266d8f30c0f6b10dd527c3f9d8c6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 30 Jun 2022 15:42:02 +0100 Subject: Use `memmove` if possible when emitting store over a certain size --- src/llvm_backend_general.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index e3d30ccff..8122f1d86 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -852,6 +852,12 @@ bool lb_is_type_proc_recursive(Type *t) { void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { GB_ASSERT(value.value != nullptr); Type *a = type_deref(ptr.type); + + if (LLVMIsNull(value.value)) { + LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value)); + LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value); + return; + } if (is_type_boolean(a)) { // NOTE(bill): There are multiple sized booleans, thus force a conversion (if necessarily) value = lb_emit_conv(p, value, a); @@ -861,6 +867,20 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { GB_ASSERT_MSG(are_types_identical(ca, core_type(value.type)), "%s != %s", type_to_string(a), type_to_string(value.type)); } + enum {MAX_STORE_SIZE = 32}; + + if (LLVMIsALoadInst(value.value) && lb_sizeof(LLVMTypeOf(value.value)) > 32) { + 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_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 -- cgit v1.2.3 From 1676c643dfd9ef45f2aaa4dfddb69cea4bcf80fc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 30 Jun 2022 15:47:19 +0100 Subject: Change MAX_STORE_SIZE --- src/llvm_backend_general.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 8122f1d86..5b43a11ab 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -867,9 +867,9 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { GB_ASSERT_MSG(are_types_identical(ca, core_type(value.type)), "%s != %s", type_to_string(a), type_to_string(value.type)); } - enum {MAX_STORE_SIZE = 32}; + enum {MAX_STORE_SIZE = 64}; - if (LLVMIsALoadInst(value.value) && lb_sizeof(LLVMTypeOf(value.value)) > 32) { + 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), ""); -- cgit v1.2.3 From e61b73d7add5893e332953ccc7825a9f7e6d25c9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 16 Jul 2022 22:30:57 +0100 Subject: Fix #1869 --- src/llvm_backend_general.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 5b43a11ab..f6bd306d2 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2369,6 +2369,9 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), 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); string_map_set(&m->const_strings, key, ptr); @@ -2411,6 +2414,9 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); LLVMSetInitializer(global_data, data); LLVMSetLinkage(global_data, LLVMPrivateLinkage); + LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr); + LLVMSetAlignment(global_data, 1); + LLVMSetGlobalConstant(global_data, true); LLVMValueRef ptr = nullptr; if (str.len != 0) { @@ -2647,6 +2653,7 @@ lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String g.type = alloc_type_pointer(t); LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, t))); LLVMSetLinkage(g.value, LLVMPrivateLinkage); + LLVMSetUnnamedAddress(g.value, LLVMGlobalUnnamedAddr); string_map_set(&m->members, s, g); return g; } -- cgit v1.2.3 From 6c7e5748a8ee80b01b99fe41192d4aac32651849 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 18 Jul 2022 12:49:29 +0100 Subject: Integrate numerous debug fixes from #1877 --- src/llvm_backend_debug.cpp | 2 +- src/llvm_backend_expr.cpp | 11 --------- src/llvm_backend_general.cpp | 8 +++---- src/llvm_backend_proc.cpp | 55 +++++++++++++++++++++++++++++++++----------- src/llvm_backend_stmt.cpp | 8 +++---- 5 files changed, 49 insertions(+), 35 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 45a868581..207164c63 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -969,7 +969,7 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T ); LLVMValueRef storage = ptr; - LLVMBasicBlockRef block = p->decl_block->block; + LLVMBasicBlockRef block = p->curr_block->block; LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos); LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0); lb_set_llvm_metadata(m, ptr, llvm_expr); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 59f75d43f..624d06188 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3068,17 +3068,6 @@ lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { return lb_const_value(p->module, type, tv.value); } - #if 0 - LLVMMetadataRef prev_debug_location = nullptr; - if (p->debug_info != nullptr) { - prev_debug_location = LLVMGetCurrentDebugLocation2(p->builder); - LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, expr)); - } - defer (if (prev_debug_location != nullptr) { - LLVMSetCurrentDebugLocation2(p->builder, prev_debug_location); - }); - #endif - switch (expr->kind) { case_ast_node(bl, BasicLit, expr); TokenPos pos = bl->token.pos; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index f6bd306d2..b2a609f85 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -2746,10 +2746,6 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p } } - if (zero_init) { - lb_mem_zero_ptr(p, ptr, type, alignment); - } - lbValue val = {}; val.value = ptr; val.type = alloc_type_pointer(type); @@ -2759,6 +2755,10 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p lb_add_debug_local_variable(p, ptr, type, e->token); } + if (zero_init) { + lb_mem_zero_ptr(p, ptr, type, alignment); + } + return lb_addr(val); } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 1c0ecabbe..0ffe1c4c7 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -434,6 +434,40 @@ void lb_start_block(lbProcedure *p, lbBlock *b) { p->curr_block = b; } +void lb_set_debug_position_to_procedure_begin(lbProcedure *p) { + if (p->debug_info == nullptr) { + return; + } + TokenPos pos = {}; + if (p->body != nullptr) { + pos = ast_token(p->body).pos; + } else if (p->type_expr != nullptr) { + pos = ast_token(p->type_expr).pos; + } else if (p->entity != nullptr) { + pos = p->entity->token.pos; + } + if (pos.file_id != 0) { + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, pos)); + } +} + +void lb_set_debug_position_to_procedure_end(lbProcedure *p) { + if (p->debug_info == nullptr) { + return; + } + TokenPos pos = {}; + if (p->body != nullptr) { + pos = ast_end_token(p->body).pos; + } else if (p->type_expr != nullptr) { + pos = ast_end_token(p->type_expr).pos; + } else if (p->entity != nullptr) { + pos = p->entity->token.pos; + } + if (pos.file_id != 0) { + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, pos)); + } +} + void lb_begin_procedure_body(lbProcedure *p) { DeclInfo *decl = decl_info_of_entity(p->entity); if (decl != nullptr) { @@ -565,29 +599,21 @@ void lb_begin_procedure_body(lbProcedure *p) { lb_push_context_onto_stack_from_implicit_parameter(p); } - lb_start_block(p, p->entry_block); - + lb_set_debug_position_to_procedure_begin(p); if (p->debug_info != nullptr) { - TokenPos pos = {}; - if (p->body != nullptr) { - pos = ast_token(p->body).pos; - } else if (p->type_expr != nullptr) { - pos = ast_token(p->type_expr).pos; - } else if (p->entity != nullptr) { - pos = p->entity->token.pos; - } - if (pos.file_id != 0) { - LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, pos)); - } - if (p->context_stack.count != 0) { + p->curr_block = p->decl_block; lb_add_debug_context_variable(p, lb_find_or_generate_context_ptr(p)); } } + + lb_start_block(p, p->entry_block); } void lb_end_procedure_body(lbProcedure *p) { + lb_set_debug_position_to_procedure_begin(p); + LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); LLVMBuildBr(p->builder, p->entry_block->block); LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); @@ -599,6 +625,7 @@ void lb_end_procedure_body(lbProcedure *p) { instr = LLVMGetLastInstruction(p->curr_block->block); if (!lb_is_instr_terminating(instr)) { lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + lb_set_debug_position_to_procedure_end(p); LLVMBuildRetVoid(p->builder); } } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 2afb5300b..d007ac747 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1721,6 +1721,9 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) { ast_node(fs, ForStmt, node); lb_open_scope(p, fs->scope); // Open Scope here + if (p->debug_info != nullptr) { + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node)); + } if (fs->init != nullptr) { #if 1 @@ -1971,14 +1974,9 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { } } - LLVMMetadataRef prev_debug_location = nullptr; if (p->debug_info != nullptr) { - prev_debug_location = LLVMGetCurrentDebugLocation2(p->builder); LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node)); } - defer (if (prev_debug_location != nullptr) { - LLVMSetCurrentDebugLocation2(p->builder, prev_debug_location); - }); u16 prev_state_flags = p->state_flags; defer (p->state_flags = prev_state_flags); -- cgit v1.2.3 From c8ab1b7ee1b1ba6444a057c6afa6a9d6eb7a7dae Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 24 Jul 2022 13:11:48 +0100 Subject: Add `#by_ptr` procedure attribute to enforce a parameter to be passed by pointer internally --- src/check_type.cpp | 20 +++++++++++++++++++- src/entity.cpp | 1 + src/llvm_backend_general.cpp | 5 +++-- src/parser.cpp | 2 ++ src/parser.hpp | 3 ++- 5 files changed, 27 insertions(+), 4 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 741385e29..dea523599 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1616,6 +1616,10 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is error(name, "'#any_int' can only be applied to variable fields"); p->flags &= ~FieldFlag_any_int; } + if (p->flags&FieldFlag_by_ptr) { + error(name, "'#by_ptr' can only be applied to variable fields"); + p->flags &= ~FieldFlag_by_ptr; + } param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved); param->TypeName.is_type_alias = true; @@ -1692,10 +1696,17 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is if (p->flags&FieldFlag_no_alias) { if (!is_type_pointer(type)) { - error(name, "'#no_alias' can only be applied to fields of pointer type"); + error(name, "'#no_alias' can only be applied pointer typed parameters"); p->flags &= ~FieldFlag_no_alias; // Remove the flag } } + if (p->flags&FieldFlag_by_ptr) { + if (is_type_internally_pointer_like(type)) { + error(name, "'#by_ptr' can only be applied to non-pointer-like parameters"); + p->flags &= ~FieldFlag_by_ptr; // Remove the flag + } + } + if (is_poly_name) { if (p->flags&FieldFlag_no_alias) { error(name, "'#no_alias' can only be applied to non constant values"); @@ -1713,6 +1724,10 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is error(name, "'#const' can only be applied to variable fields"); p->flags &= ~FieldFlag_const; } + if (p->flags&FieldFlag_by_ptr) { + error(name, "'#by_ptr' can only be applied to variable fields"); + p->flags &= ~FieldFlag_by_ptr; + } if (!is_type_constant_type(type) && !is_type_polymorphic(type)) { gbString str = type_to_string(type); @@ -1745,6 +1760,9 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is if (p->flags&FieldFlag_const) { param->flags |= EntityFlag_ConstInput; } + if (p->flags&FieldFlag_by_ptr) { + param->flags |= EntityFlag_ByPtr; + } param->state = EntityState_Resolved; // NOTE(bill): This should have be resolved whilst determining it add_entity(ctx, scope, name, param); diff --git a/src/entity.cpp b/src/entity.cpp index 76e6912b9..3d3712328 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -83,6 +83,7 @@ enum EntityFlag : u64 { EntityFlag_CustomLinkage_LinkOnce = 1ull<<44, EntityFlag_Require = 1ull<<50, + EntityFlag_ByPtr = 1ull<<51, // enforce parameter is passed by pointer EntityFlag_Overridden = 1ull<<63, }; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index b2a609f85..a4c2ce370 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1958,11 +1958,12 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { if (e->flags & EntityFlag_CVarArg) { continue; } - Type *e_type = reduce_tuple_to_single_type(e->type); LLVMTypeRef param_type = nullptr; - if (is_type_boolean(e_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) { param_type = LLVMInt1TypeInContext(m->ctx); } else { diff --git a/src/parser.cpp b/src/parser.cpp index dd9d6f036..247255ce8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3561,6 +3561,7 @@ enum FieldPrefixKind : i32 { FieldPrefix_auto_cast, FieldPrefix_any_int, FieldPrefix_subtype, // does not imply `using` semantics + FieldPrefix_by_ptr, }; struct ParseFieldPrefixMapping { @@ -3578,6 +3579,7 @@ gb_global ParseFieldPrefixMapping parse_field_prefix_mappings[] = { {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}, }; diff --git a/src/parser.hpp b/src/parser.hpp index 8719b5e56..3126e0a02 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -302,13 +302,14 @@ enum FieldFlag : u32 { FieldFlag_const = 1<<5, FieldFlag_any_int = 1<<6, FieldFlag_subtype = 1<<7, + FieldFlag_by_ptr = 1<<8, // Internal use by the parser only FieldFlag_Tags = 1<<10, FieldFlag_Results = 1<<16, // Parameter List Restrictions - FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int, + 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 e6ab4f48567175cc192a658fb6d7b067e38912d8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 24 Jul 2022 20:22:50 +0100 Subject: Force memset instead of store zeroinitializer when the value is large --- src/llvm_backend.hpp | 4 ++++ src/llvm_backend_general.cpp | 12 +++++++++--- src/llvm_backend_stmt.cpp | 3 ++- src/llvm_backend_utility.cpp | 8 ++++---- 4 files changed, 19 insertions(+), 8 deletions(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 745dbbbc7..a09286d0b 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -482,7 +482,11 @@ LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRe 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); +i64 lb_max_zero_init_size(void) { + return cast(i64)(4*build_context.word_size); +} #define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" #define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index a4c2ce370..52787d427 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -855,7 +855,11 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { if (LLVMIsNull(value.value)) { LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value)); - LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value); + 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, LLVMGetAlignment(ptr.value)); + } return; } if (is_type_boolean(a)) { @@ -2737,13 +2741,15 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p if (!zero_init && !force_no_init) { // If there is any padding of any kind, just zero init regardless of zero_init parameter LLVMTypeKind kind = LLVMGetTypeKind(llvm_type); + if (kind == LLVMArrayTypeKind) { + kind = LLVMGetTypeKind(lb_type(p->module, core_array_type(type))); + } + if (kind == LLVMStructTypeKind) { i64 sz = type_size_of(type); if (type_size_of_struct_pretend_is_packed(type) != sz) { zero_init = true; } - } else if (kind == LLVMArrayTypeKind) { - zero_init = true; } } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index a8f543c1f..f131bb3db 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -2082,7 +2082,8 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { lbAddr lval = {}; if (!is_blank_ident(name)) { Entity *e = entity_of_node(name); - bool zero_init = true; // Always do it + // bool zero_init = true; // Always do it + bool zero_init = vd->values.count == 0; lval = lb_add_local(p, e->type, e, zero_init); } array_add(&lvals, lval); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 2fa43bb0a..88ec2f22c 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -50,14 +50,14 @@ lbValue lb_correct_endianness(lbProcedure *p, lbValue value) { return value; } -void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) { +LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) { bool is_inlinable = false; i64 const_len = 0; if (LLVMIsConstant(len)) { const_len = cast(i64)LLVMConstIntGetSExtValue(len); // TODO(bill): Determine when it is better to do the `*.inline` versions - if (const_len <= 4*build_context.word_size) { + if (const_len <= lb_max_zero_init_size()) { is_inlinable = true; } } @@ -83,7 +83,7 @@ void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, ""); args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), is_volatile, false); - LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + return LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); } else { LLVMValueRef ip = lb_lookup_runtime_procedure(p->module, str_lit("memset")).value; @@ -92,7 +92,7 @@ void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len args[1] = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), 0, false); args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, ""); - LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); + return LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); } } -- cgit v1.2.3 From b28d4b753b1a3b52f90e215218e63ef9bf455bc9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 24 Jul 2022 20:58:50 +0100 Subject: Temp fix for `lb_emit_store` --- src/llvm_backend_general.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/llvm_backend_general.cpp') diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 52787d427..b61439238 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -858,7 +858,7 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { 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, LLVMGetAlignment(ptr.value)); + lb_mem_zero_ptr(p, ptr.value, a, 1); } return; } -- 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/llvm_backend_general.cpp') 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 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/llvm_backend_general.cpp') 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/llvm_backend_general.cpp') 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/llvm_backend_general.cpp') 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 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/llvm_backend_general.cpp') 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 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/llvm_backend_general.cpp') 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/llvm_backend_general.cpp') 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 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/llvm_backend_general.cpp') 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/llvm_backend_general.cpp') 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