diff options
| author | gingerBill <bill@gingerbill.org> | 2019-11-03 00:32:22 +0000 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2019-11-03 00:32:22 +0000 |
| commit | ebf7926fa495a7a2d400f44beb4c27888bda33e5 (patch) | |
| tree | 231fe45243a069904c98c03acae05751625d7f71 | |
| parent | dfb3101ecf59797884cb959b3bfeda49ccfa3223 (diff) | |
SOA support of Structures and Arrays; Runtime information for SOA structs; fmt printing support for SOA structs
| -rw-r--r-- | core/fmt/fmt.odin | 82 | ||||
| -rw-r--r-- | core/runtime/core.odin | 3 | ||||
| -rw-r--r-- | src/check_expr.cpp | 91 | ||||
| -rw-r--r-- | src/ir.cpp | 28 | ||||
| -rw-r--r-- | src/types.cpp | 17 |
5 files changed, 172 insertions, 49 deletions
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'); + defer { + if hash do for in 0..<indent do strings.write_byte(fi.buf, '\t'); + strings.write_byte(fi.buf, is_soa ? ']' : '}'); + } - field_count := -1; - for name, i in b.names { - // if len(name) > 0 && name[0] == '_' do continue; - field_count += 1; + if is_soa { + indent := fi.indent; defer fi.indent -= 1; + fi.indent += 1; - if !hash && field_count > 0 do strings.write_string(fi.buf, ", "); - if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t'); + base_type_name: string; + if v, ok := b.soa_base_type.variant.(runtime.Type_Info_Named); ok { + base_type_name = v.name; + } - strings.write_string(fi.buf, name); - strings.write_string(fi.buf, " = "); + for index in 0..<uintptr(b.soa_len) { + if !hash && index > 0 do strings.write_string(fi.buf, ", "); - if t := b.types[i]; reflect.is_any(t) { - strings.write_string(fi.buf, "any{}"); - } else { - data := rawptr(uintptr(v.data) + b.offsets[i]); - fmt_arg(fi, any{data, t.id}, 'v'); + 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..<fi.indent do strings.write_byte(fi.buf, '\t'); + + strings.write_string(fi.buf, name); + strings.write_string(fi.buf, " = "); + + t := b.types[i].variant.(runtime.Type_Info_Array).elem; + t_size := uintptr(t.size); + if reflect.is_any(t) { + strings.write_string(fi.buf, "any{}"); + } else { + data := rawptr(uintptr(v.data) + b.offsets[i] + index*t_size); + fmt_arg(fi, any{data, t.id}, 'v'); + } + + if hash do strings.write_string(fi.buf, ",\n"); + } } + } else { + field_count := -1; + for name, i in b.names { + field_count += 1; - if hash do strings.write_string(fi.buf, ",\n"); - } + if !hash && field_count > 0 do strings.write_string(fi.buf, ", "); + if hash do for in 0..<fi.indent do strings.write_byte(fi.buf, '\t'); - if hash do for in 0..<indent do strings.write_byte(fi.buf, '\t'); - strings.write_byte(fi.buf, '}'); + strings.write_string(fi.buf, name); + strings.write_string(fi.buf, " = "); + + if t := b.types[i]; reflect.is_any(t) { + strings.write_string(fi.buf, "any{}"); + } else { + data := rawptr(uintptr(v.data) + b.offsets[i]); + fmt_arg(fi, any{data, t.id}, 'v'); + } + + if hash do strings.write_string(fi.buf, ",\n"); + } + } case runtime.Type_Info_Bit_Set: fmt_bit_set(fi, v); diff --git a/core/runtime/core.odin b/core/runtime/core.odin index 7ba98ae30..30555956e 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -87,6 +87,9 @@ Type_Info_Struct :: struct { is_packed: bool, is_raw_union: bool, custom_align: bool, + // These are only set iff this structure is an SOA structure + soa_base_type: ^Type_Info, + soa_len: int, }; Type_Info_Union :: struct { variants: []^Type_Info, diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8691e8fe0..9db4938ee 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3616,6 +3616,13 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 mode = Addressing_Constant; value = exact_value_i64(bt->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 *old_struct = base_type(elem); - Type *soa_struct = alloc_type_struct(); - soa_struct->Struct.fields = array_make<Entity *>(heap_allocator(), old_struct->Struct.fields.count); - soa_struct->Struct.tags = array_make<String>(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 *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); + Type *soa_struct = nullptr; + Scope *scope = nullptr; + + if (is_type_array(elem)) { + Type *old_array = base_type(elem); + soa_struct = alloc_type_struct(); + soa_struct->Struct.fields = array_make<Entity *>(heap_allocator(), old_array->Array.count); + soa_struct->Struct.tags = array_make<String>(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 = create_scope(c->scope, c->allocator); + soa_struct->Struct.scope = scope; + + 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<Entity *>(heap_allocator(), old_struct->Struct.fields.count); + soa_struct->Struct.tags = array_make<String>(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]; |