diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index e6830e734..39652e012 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -1085,8 +1085,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { strings.write_string(fi.buf, "{}"); return; }; + + is_soa := b.soa_base_type != nil; + strings.write_string(fi.buf, info.name); - strings.write_byte(fi.buf, '{'); + strings.write_byte(fi.buf, is_soa ? '[' : '{'); hash := fi.hash; defer fi.hash = hash; indent := fi.indent; defer fi.indent -= 1; @@ -1095,30 +1098,73 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) { fi.indent += 1; if hash do strings.write_byte(fi.buf, '\n'); - - field_count := -1; - for name, i in b.names { - // if len(name) > 0 && name[0] == '_' do continue; - field_count += 1; - - if !hash && field_count > 0 do strings.write_string(fi.buf, ", "); - if hash do for in 0.. 0 do strings.write_string(fi.buf, ", "); + + field_count := -1; + + if !hash && field_count > 0 do strings.write_string(fi.buf, ", "); + + strings.write_string(fi.buf, base_type_name); + strings.write_byte(fi.buf, '{'); + defer strings.write_byte(fi.buf, '}'); + + for name, i in b.names { + field_count += 1; + + if !hash && field_count > 0 do strings.write_string(fi.buf, ", "); + if hash do for in 0.. 0 do strings.write_string(fi.buf, ", "); + if hash do for in 0..Enum.fields.count); type = t_untyped_integer; + } else if (is_type_struct(op_type)) { + Type *bt = base_type(op_type); + if (bt->Struct.is_soa) { + mode = Addressing_Constant; + value = exact_value_i64(bt->Struct.soa_count); + type = t_untyped_integer; + } } if (mode == Addressing_Invalid) { @@ -4761,9 +4768,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 return false; } Type *elem = y.type; - if (!is_type_struct(elem) && !is_type_raw_union(elem)) { + Type *bt_elem = base_type(elem); + if (!is_type_struct(elem) && !is_type_raw_union(elem) && !(is_type_array(elem) && bt_elem->Array.count <= 4)) { gbString str = type_to_string(elem); - error(call, "Invalid type for 'intrinsics.soa_struct', expected a struct, got '%s'", str); + error(call, "Invalid type for 'intrinsics.soa_struct', expected a struct or array of length 4 or below, got '%s'", str); gb_string_free(str); operand->mode = Addressing_Type; operand->type = t_invalid; @@ -4771,33 +4779,68 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 } operand->mode = Addressing_Type; + Type *soa_struct = nullptr; + Scope *scope = nullptr; - Type *old_struct = base_type(elem); - Type *soa_struct = alloc_type_struct(); - soa_struct->Struct.fields = array_make(heap_allocator(), old_struct->Struct.fields.count); - soa_struct->Struct.tags = array_make(heap_allocator(), old_struct->Struct.tags.count); - soa_struct->Struct.node = operand->expr; - soa_struct->Struct.is_soa = true; - soa_struct->Struct.soa_elem = elem; - soa_struct->Struct.soa_count = count; + if (is_type_array(elem)) { + Type *old_array = base_type(elem); + soa_struct = alloc_type_struct(); + soa_struct->Struct.fields = array_make(heap_allocator(), old_array->Array.count); + soa_struct->Struct.tags = array_make(heap_allocator(), old_array->Array.count); + soa_struct->Struct.node = operand->expr; + soa_struct->Struct.is_soa = true; + soa_struct->Struct.soa_elem = elem; + soa_struct->Struct.soa_count = count; - Scope *scope = create_scope(old_struct->Struct.scope->parent, c->allocator); - soa_struct->Struct.scope = scope; + scope = create_scope(c->scope, c->allocator); + soa_struct->Struct.scope = scope; - for_array(i, old_struct->Struct.fields) { - Entity *old_field = old_struct->Struct.fields[i]; - if (old_field->kind == Entity_Variable) { - Type *array_type = alloc_type_array(old_field->type, count); - Entity *new_field = alloc_entity_field(scope, old_field->token, array_type, false, old_field->Variable.field_src_index); + String params_xyzw[4] = { + str_lit("x"), + str_lit("y"), + str_lit("z"), + str_lit("w") + }; + + for (i64 i = 0; i < old_array->Array.count; i++) { + Type *array_type = alloc_type_array(old_array->Array.elem, count); + Token token = {}; + token.string = params_xyzw[i]; + + Entity *new_field = alloc_entity_field(scope, token, array_type, false, cast(i32)i); soa_struct->Struct.fields[i] = new_field; add_entity(c->checker, scope, nullptr, new_field); - } else { - soa_struct->Struct.fields[i] = old_field; } - soa_struct->Struct.tags[i] = old_struct->Struct.tags[i]; - } + } else { + GB_ASSERT(is_type_struct(elem)); + Type *old_struct = base_type(elem); + soa_struct = alloc_type_struct(); + soa_struct->Struct.fields = array_make(heap_allocator(), old_struct->Struct.fields.count); + soa_struct->Struct.tags = array_make(heap_allocator(), old_struct->Struct.tags.count); + soa_struct->Struct.node = operand->expr; + soa_struct->Struct.is_soa = true; + soa_struct->Struct.soa_elem = elem; + soa_struct->Struct.soa_count = count; + + scope = create_scope(old_struct->Struct.scope->parent, c->allocator); + soa_struct->Struct.scope = scope; + + for_array(i, old_struct->Struct.fields) { + Entity *old_field = old_struct->Struct.fields[i]; + if (old_field->kind == Entity_Variable) { + Type *array_type = alloc_type_array(old_field->type, count); + Entity *new_field = alloc_entity_field(scope, old_field->token, array_type, false, old_field->Variable.field_src_index); + soa_struct->Struct.fields[i] = new_field; + add_entity(c->checker, scope, nullptr, new_field); + } else { + soa_struct->Struct.fields[i] = old_field; + } + + soa_struct->Struct.tags[i] = old_struct->Struct.tags[i]; + } + } Token token = {}; token.string = str_lit("Base_Type"); diff --git a/src/ir.cpp b/src/ir.cpp index 74ddaf262..fb10e946f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4553,6 +4553,8 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { case 0: result_type = alloc_type_pointer(gst->Struct.fields[0]->type); break; case 1: result_type = alloc_type_pointer(gst->Struct.fields[1]->type); break; } + } else if (is_type_array(t)) { + return ir_emit_array_epi(proc, s, index); } else { GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(ir_type(s)), index); } @@ -4632,15 +4634,20 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) { } break; - case Type_Map: { - init_map_internal_types(t); - Type *gst = t->Map.generated_struct_type; - switch (index) { - case 0: result_type = gst->Struct.fields[0]->type; break; - case 1: result_type = gst->Struct.fields[1]->type; break; + case Type_Map: + { + init_map_internal_types(t); + Type *gst = t->Map.generated_struct_type; + switch (index) { + case 0: result_type = gst->Struct.fields[0]->type; break; + case 1: result_type = gst->Struct.fields[1]->type; break; + } } break; - } + + case Type_Array: + result_type = t->Array.elem; + break; default: GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(ir_type(s)), index); @@ -10849,6 +10856,13 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_packed); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union); ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align); + + if (t->Struct.is_soa) { + irValue *soa_type = ir_type_info(proc, t->Struct.soa_elem); + irValue *soa_len = ir_const_int(t->Struct.soa_count); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 8), soa_type); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 9), soa_len); + } } isize count = t->Struct.fields.count; diff --git a/src/types.cpp b/src/types.cpp index 6fab6643e..ac78bb943 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1133,6 +1133,10 @@ bool is_type_union(Type *t) { t = base_type(t); return t->kind == Type_Union; } +bool is_type_soa_struct(Type *t) { + t = base_type(t); + return t->kind == Type_Struct && t->Struct.is_soa; +} bool is_type_raw_union(Type *t) { t = base_type(t); @@ -2194,6 +2198,19 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty sel.index.count = prev_count; } } + + bool is_soa = type->Struct.is_soa; + bool is_soa_of_array = is_soa && is_type_array(type->Struct.soa_elem); + + if (is_soa_of_array) { + String mapped_field_name = {}; + if (field_name == "r") mapped_field_name = str_lit("x"); + else if (field_name == "g") mapped_field_name = str_lit("y"); + else if (field_name == "b") mapped_field_name = str_lit("z"); + else if (field_name == "a") mapped_field_name = str_lit("w"); + return lookup_field_with_selection(type, mapped_field_name, is_type, sel, allow_blank_ident); + } + } else if (type->kind == Type_BitField) { for_array(i, type->BitField.fields) { Entity *f = type->BitField.fields[i];