diff --git a/base/runtime/core_builtin_soa.odin b/base/runtime/core_builtin_soa.odin index 23f879791..547df0a2b 100644 --- a/base/runtime/core_builtin_soa.odin +++ b/base/runtime/core_builtin_soa.odin @@ -102,7 +102,7 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, alloc total_size := 0 for i in 0.. (res: string) { - s := transmute(string)mem.Raw_String{ptr, len} +string_from_null_terminated_ptr :: proc(ptr: [^]byte, len: int) -> (res: string) { + s := string(ptr[:len]) s = truncate_to_byte(s, 0) return s } diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 80a8705ea..7e41c610a 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -3442,8 +3442,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As auto types = slice_make(permanent_allocator(), t->Struct.fields.count-1); for_array(i, types) { Entity *f = t->Struct.fields[i]; - GB_ASSERT(f->type->kind == Type_Pointer); - types[i] = alloc_type_slice(f->type->Pointer.elem); + GB_ASSERT(f->type->kind == Type_MultiPointer); + types[i] = alloc_type_slice(f->type->MultiPointer.elem); } operand->type = alloc_type_tuple_from_field_types(types.data, types.count, false, false); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 0222124d4..d08f47a25 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7808,8 +7808,8 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 if (is_type_pointer(original_type) && indirection) { Type *ptr = base_type(original_type); - if (ptr->kind == Type_Pointer && o->mode == Addressing_SoaVariable) { - o->type = ptr->Pointer.elem; + if (ptr->kind == Type_MultiPointer && o->mode == Addressing_SoaVariable) { + o->type = ptr->MultiPointer.elem; o->mode = Addressing_Value; return true; } diff --git a/src/check_type.cpp b/src/check_type.cpp index c209a8e09..9381443fc 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2827,12 +2827,15 @@ gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finis GB_ASSERT(soa_count >= 0); field_type = alloc_type_array(old_field->type, soa_count); } else { - field_type = alloc_type_pointer(old_field->type); + field_type = alloc_type_multi_pointer(old_field->type); } Entity *new_field = alloc_entity_field(scope, old_field->token, field_type, false, old_field->Variable.field_index); t->Struct.fields[i] = new_field; add_entity(scope, new_field); new_field->flags |= EntityFlag_Used; + if (t->Struct.soa_kind != StructSoa_Fixed) { + new_field->flags |= EntityFlag_SoaPtrField; + } } else { t->Struct.fields[i] = old_field; } @@ -2948,7 +2951,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e GB_ASSERT(count >= 0); field_type = alloc_type_array(old_array->Array.elem, count); } else { - field_type = alloc_type_pointer(old_array->Array.elem); + field_type = alloc_type_multi_pointer(old_array->Array.elem); } Token token = {}; token.string = params_xyzw[i]; @@ -2957,6 +2960,9 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e soa_struct->Struct.fields[i] = new_field; add_entity(ctx, scope, nullptr, new_field); add_entity_use(ctx, nullptr, new_field); + if (soa_kind != StructSoa_Fixed) { + new_field->flags |= EntityFlag_SoaPtrField; + } } is_complete = true; @@ -2980,12 +2986,15 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e GB_ASSERT(count >= 0); field_type = alloc_type_array(old_field->type, count); } else { - field_type = alloc_type_pointer(old_field->type); + field_type = alloc_type_multi_pointer(old_field->type); } Entity *new_field = alloc_entity_field(scope, old_field->token, field_type, false, old_field->Variable.field_index); soa_struct->Struct.fields[i] = new_field; add_entity(ctx, scope, nullptr, new_field); add_entity_use(ctx, nullptr, new_field); + if (soa_kind != StructSoa_Fixed) { + new_field->flags |= EntityFlag_SoaPtrField; + } } else { soa_struct->Struct.fields[i] = old_field; } diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 8035336d3..3ed8d72d9 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -539,7 +539,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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); + lbAddr slice = lb_add_local_generated(p, original_type, false); map_set(&m->exact_value_compound_literal_addr_map, value.value_compound, slice); lb_fill_slice(p, slice, {ptr, alloc_type_pointer(elem)}, {len, t_int}); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 899b74e56..c12489598 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3851,27 +3851,39 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { if (ie->expr->tav.mode == Addressing_SoaVariable) { // SOA Structures for slices/dynamic arrays - GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); + GB_ASSERT_MSG(is_type_multi_pointer(type_of_expr(ie->expr)), "%s", type_to_string(type_of_expr(ie->expr))); lbValue field = lb_build_expr(p, ie->expr); lbValue index = lb_build_expr(p, ie->index); - if (!build_context.no_bounds_check) { - // TODO HACK(bill): Clean up this hack to get the length for bounds checking - // GB_ASSERT(LLVMIsALoadInst(field.value)); + Ast *se_expr = unparen_expr(ie->expr); + if (se_expr->kind == Ast_SelectorExpr) { + ast_node(se, SelectorExpr, se_expr); + lbValue len = {}; - // lbValue a = {}; - // a.value = LLVMGetOperand(field.value, 0); - // a.type = alloc_type_pointer(field.type); + Type *type = base_type(type_deref(type_of_expr(se->expr))); + GB_ASSERT_MSG(is_type_soa_struct(type), "%s", type_to_string(type)); + if (type->Struct.soa_kind == StructSoa_Fixed) { + len = lb_const_int(p->module, t_int, type->Struct.soa_count); + } else { + lbAddr *found = map_get(&p->selector_addr, se_expr); + if (found) { + lbAddr addr = *found; + lbValue parent = lb_addr_get_ptr(p, addr); + if (is_type_pointer(type_deref(parent.type))) { + parent = lb_emit_load(p, parent); + } + len = lb_soa_struct_len(p, parent); + } + } - // 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); + if (len.value) { + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + } else { + // TODO(bill): how do you even do bounds checking here? + } } lbValue val = lb_emit_ptr_offset(p, field, index); return lb_addr(val); @@ -4218,6 +4230,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); field_src = lb_emit_array_ep(p, field_src, low); + field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type)); lb_emit_store(p, field_dst, field_src); } @@ -4233,6 +4246,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); lbValue field_src = lb_emit_struct_ev(p, base, i); field_src = lb_emit_ptr_offset(p, field_src, low); + field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type)); lb_emit_store(p, field_dst, field_src); } @@ -4247,6 +4261,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); lbValue field_src = lb_emit_struct_ev(p, base, i); field_src = lb_emit_ptr_offset(p, field_src, low); + field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type)); lb_emit_store(p, field_dst, field_src); } @@ -4978,6 +4993,9 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { if (sub_sel.index.count > 0) { item = lb_emit_deep_field_gep(p, item, sub_sel); } + // make sure it's ^T and not [^]T + item.type = alloc_type_multi_pointer_to_pointer(item.type); + return lb_addr(item); } else if (addr.kind == lbAddr_Swizzle) { GB_ASSERT(sel.index.count > 0); @@ -4989,6 +5007,11 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { sel.index[0] = addr.swizzle.indices[sel.index[0]]; } + Type *atype = type_deref(lb_addr_type(addr)); + if (is_type_soa_struct(atype)) { + map_set(&p->selector_addr, expr, addr); + } + lbValue a = lb_addr_get_ptr(p, addr); a = lb_emit_deep_field_gep(p, a, sel); return lb_addr(a); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 3c1a7ee7f..e8183027f 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1324,7 +1324,7 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { for (isize i = 0; i < field_count; i++) { Entity *field = t->Struct.fields[i]; Type *base_type = field->type; - GB_ASSERT(base_type->kind == Type_Pointer); + GB_ASSERT(base_type->kind == Type_MultiPointer); lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i); lbValue src_ptr = lb_emit_struct_ep(p, addr.addr, cast(i32)i); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 8b046c784..5ebe0ddd9 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -328,6 +328,7 @@ gb_internal lbValue lb_soa_zip(lbProcedure *p, AstCallExpr *ce, TypeAndValue con lbAddr res = lb_add_local_generated(p, tv.type, true); for_array(i, slices) { lbValue src = lb_slice_elem(p, slices[i]); + src = lb_emit_conv(p, src, alloc_type_pointer_to_multi_pointer(src.type)); lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i); lb_emit_store(p, dst, src); } @@ -1559,19 +1560,26 @@ gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isiz return lb_emit_load(p, ptr); } - gb_internal void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len) { Type *t = lb_addr_type(slice); GB_ASSERT(is_type_slice(t)); lbValue ptr = lb_addr_get_ptr(p, slice); - lb_emit_store(p, lb_emit_struct_ep(p, ptr, 0), base_elem); + lbValue data = lb_emit_struct_ep(p, ptr, 0); + if (are_types_identical(type_deref(base_elem.type, true), type_deref(type_deref(data.type), true))) { + base_elem = lb_emit_conv(p, base_elem, type_deref(data.type)); + } + lb_emit_store(p, data, base_elem); lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len); } gb_internal void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue base_elem, lbValue len) { Type *t = lb_addr_type(string); GB_ASSERT(is_type_string(t)); lbValue ptr = lb_addr_get_ptr(p, string); - lb_emit_store(p, lb_emit_struct_ep(p, ptr, 0), base_elem); + lbValue data = lb_emit_struct_ep(p, ptr, 0); + if (are_types_identical(type_deref(base_elem.type, true), type_deref(type_deref(data.type), true))) { + base_elem = lb_emit_conv(p, base_elem, type_deref(data.type)); + } + lb_emit_store(p, data, base_elem); lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len); } diff --git a/src/types.cpp b/src/types.cpp index 47ed86f7a..e568d2af2 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -988,6 +988,27 @@ gb_internal Type *alloc_type_soa_pointer(Type *elem) { return t; } +gb_internal Type *alloc_type_pointer_to_multi_pointer(Type *ptr) { + Type *original_type = ptr; + ptr = base_type(ptr); + if (ptr->kind == Type_Pointer) { + return alloc_type_multi_pointer(ptr->Pointer.elem); + } else if (ptr->kind != Type_MultiPointer) { + GB_PANIC("Invalid type: %s", type_to_string(original_type)); + } + return original_type; +} + +gb_internal Type *alloc_type_multi_pointer_to_pointer(Type *ptr) { + Type *original_type = ptr; + ptr = base_type(ptr); + if (ptr->kind == Type_MultiPointer) { + return alloc_type_pointer(ptr->MultiPointer.elem); + } else if (ptr->kind != Type_Pointer) { + GB_PANIC("Invalid type: %s", type_to_string(original_type)); + } + return original_type; +} gb_internal Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = nullptr) { if (generic_count != nullptr) {