From 041625381cfd6236de5bc5fea3a398123b7328ed Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 16 Jul 2022 17:36:03 +0100 Subject: Fix #1888 --- src/check_expr.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b42301cd6..13d6badbe 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8643,6 +8643,8 @@ ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type Ast *first_arg = x.expr->SelectorExpr.expr; GB_ASSERT(first_arg != nullptr); + first_arg->state_flags |= StateFlag_SelectorCallExpr; + Type *pt = base_type(x.type); GB_ASSERT(pt->kind == Type_Proc); Type *first_type = nullptr; @@ -8668,6 +8670,7 @@ ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type y.mode = first_arg->tav.mode; y.type = first_arg->tav.type; y.value = first_arg->tav.value; + if (check_is_assignable_to(c, &y, first_type)) { // Do nothing, it's valid } else { @@ -10034,9 +10037,10 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) { str = write_expr_to_string(str, ce->proc, shorthand); str = gb_string_appendc(str, "("); - for_array(i, ce->args) { + isize idx0 = cast(isize)ce->was_selector; + for (isize i = idx0; i < ce->args.count; i++) { Ast *arg = ce->args[i]; - if (i > 0) { + if (i > idx0) { str = gb_string_appendc(str, ", "); } str = write_expr_to_string(str, arg, shorthand); -- cgit v1.2.3 From eafa5098aa5fd10554f3348acba5ac6164a4b83e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 16 Jul 2022 18:03:43 +0100 Subject: Fix #1883 --- src/check_expr.cpp | 35 +++++++++++++++++++++-------------- src/llvm_backend_const.cpp | 23 +++++++++++------------ 2 files changed, 32 insertions(+), 26 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 13d6badbe..721b5a5af 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8404,23 +8404,30 @@ ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type * if (is_type_bit_set(type)) { // NOTE(bill): Encode as an integer - i64 lower = base_type(type)->BitSet.lower; + Type *bt = base_type(type); + BigInt bits = {}; + BigInt one = {}; + big_int_from_u64(&one, 1); - u64 bits = 0; - for_array(index, cl->elems) { - Ast *elem = cl->elems[index]; - GB_ASSERT(elem->kind != Ast_FieldValue); - TypeAndValue tav = elem->tav; - ExactValue i = exact_value_to_integer(tav.value); - if (i.kind != ExactValue_Integer) { + for_array(i, cl->elems) { + Ast *e = cl->elems[i]; + GB_ASSERT(e->kind != Ast_FieldValue); + + TypeAndValue tav = e->tav; + if (tav.mode != Addressing_Constant) { continue; } - i64 val = big_int_to_i64(&i.value_integer); - val -= lower; - u64 bit = u64(1ll<value = exact_value_u64(bits); + GB_ASSERT(tav.value.kind == ExactValue_Integer); + i64 v = big_int_to_i64(&tav.value.value_integer); + i64 lower = bt->BitSet.lower; + u64 index = cast(u64)(v-lower); + BigInt bit = {}; + big_int_from_u64(&bit, index); + big_int_shl(&bit, &one, &bit); + big_int_or(&bits, &bits, &bit); + } + o->value.kind = ExactValue_Integer; + o->value.value_integer = bits; } else if (is_type_constant_type(type) && cl->elems.count == 0) { ExactValue value = exact_value_compound(node); Type *bt = core_type(type); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 00452eb50..24b2bc3a2 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1025,7 +1025,10 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc return lb_const_nil(m, original_type); } - u64 bits = 0; + BigInt bits = {}; + BigInt one = {}; + big_int_from_u64(&one, 1); + for_array(i, cl->elems) { Ast *e = cl->elems[i]; GB_ASSERT(e->kind != Ast_FieldValue); @@ -1037,18 +1040,14 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc GB_ASSERT(tav.value.kind == ExactValue_Integer); i64 v = big_int_to_i64(&tav.value.value_integer); i64 lower = type->BitSet.lower; - bits |= 1ull< Date: Sun, 24 Jul 2022 12:59:34 +0100 Subject: Fix #1493 --- src/check_expr.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 721b5a5af..ff1745535 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2959,7 +2959,14 @@ void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand goto matrix_error; } x->mode = Addressing_Value; - x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count); + if (are_types_identical(xt, yt)) { + if (!is_type_named(x->type) && is_type_named(y->type)) { + // prefer the named type + x->type = y->type; + } + } else { + x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count); + } goto matrix_success; } else if (yt->kind == Type_Array) { if (!are_types_identical(xt->Matrix.elem, yt->Array.elem)) { @@ -3021,7 +3028,6 @@ void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand matrix_success: x->type = check_matrix_type_hint(x->type, type_hint); - return; -- cgit v1.2.3 From 0ebe9ba4871d614fac6feb9d66ffe9c3892c1517 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 24 Jul 2022 22:51:34 +0100 Subject: Fix #1901 --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ff1745535..cf9f2f751 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9302,7 +9302,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type check_unary_expr(c, o, ue->op, node); } o->expr = node; - return kind; + return Expr_Expr; case_end; -- cgit v1.2.3 From a58e4d035964275ade5e09fa6bcafb5d46cc46e2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 5 Aug 2022 12:19:57 +0100 Subject: Allow for `foo() or_else unreachable()` and other diverging procedures --- src/check_expr.cpp | 26 +++++++++++++++-- src/llvm_backend_proc.cpp | 2 +- src/llvm_backend_utility.cpp | 69 +++++++++++++++++++++++++++++--------------- 3 files changed, 70 insertions(+), 27 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cf9f2f751..96adde013 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -119,6 +119,7 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint); void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); +bool is_diverging_expr(Ast *expr); void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { auto results = did_you_mean_results(d); @@ -7399,8 +7400,25 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type return Expr_Expr; } - check_multi_expr_with_type_hint(c, &y, default_value, x.type); - error_operand_no_value(&y); + bool y_is_diverging = false; + check_expr_base(c, &y, default_value, x.type); + switch (y.mode) { + case Addressing_NoValue: + if (is_diverging_expr(y.expr)) { + // Allow + y.mode = Addressing_Value; + y_is_diverging = true; + } else { + error_operand_no_value(&y); + y.mode = Addressing_Invalid; + } + break; + case Addressing_Type: + error_operand_not_expression(&y); + y.mode = Addressing_Invalid; + break; + } + if (y.mode == Addressing_Invalid) { o->mode = Addressing_Value; o->type = t_invalid; @@ -7414,7 +7432,9 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value); if (left_type != nullptr) { - check_assignment(c, &y, left_type, name); + if (!y_is_diverging) { + check_assignment(c, &y, left_type, name); + } } else { check_or_else_expr_no_value_error(c, name, x, type_hint); } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index a026356a2..67f008a35 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1852,7 +1852,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } case BuiltinProc_unreachable: - LLVMBuildUnreachable(p->builder); + lb_emit_unreachable(p); return {}; diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 88ec2f22c..bbacce7a2 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -39,6 +39,12 @@ bool lb_is_type_aggregate(Type *t) { return false; } +void lb_emit_unreachable(lbProcedure *p) { + LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block); + if (instr == nullptr || !lb_is_instr_terminating(instr)) { + LLVMBuildUnreachable(p->builder); + } +} lbValue lb_correct_endianness(lbProcedure *p, lbValue value) { Type *src = core_type(value.type); @@ -350,40 +356,57 @@ lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue c lbValue rhs = {}; lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs); - LLVMValueRef incoming_values[2] = {}; - LLVMBasicBlockRef incoming_blocks[2] = {}; - GB_ASSERT(else_expr != nullptr); - lbBlock *then = lb_create_block(p, "or_else.then"); - lbBlock *done = lb_create_block(p, "or_else.done"); // NOTE(bill): Append later - lbBlock *else_ = lb_create_block(p, "or_else.else"); - - lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); - lb_start_block(p, then); Type *type = default_type(tv.type); - incoming_values[0] = lb_emit_conv(p, lhs, type).value; + if (is_diverging_expr(else_expr)) { + lbBlock *then = lb_create_block(p, "or_else.then"); + lbBlock *else_ = lb_create_block(p, "or_else.else"); - lb_emit_jump(p, done); - lb_start_block(p, else_); + lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); + // NOTE(bill): else block needs to be straight afterwards to make sure that the actual value is used + // from the then block + lb_start_block(p, else_); - incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, else_expr), type).value; + lb_build_expr(p, else_expr); + lb_emit_unreachable(p); // add just in case - lb_emit_jump(p, done); - lb_start_block(p, done); + lb_start_block(p, then); + return lb_emit_conv(p, lhs, type); + } else { + LLVMValueRef incoming_values[2] = {}; + LLVMBasicBlockRef incoming_blocks[2] = {}; - lbValue res = {}; - res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), ""); - res.type = type; + lbBlock *then = lb_create_block(p, "or_else.then"); + lbBlock *done = lb_create_block(p, "or_else.done"); // NOTE(bill): Append later + lbBlock *else_ = lb_create_block(p, "or_else.else"); - GB_ASSERT(p->curr_block->preds.count >= 2); - incoming_blocks[0] = p->curr_block->preds[0]->block; - incoming_blocks[1] = p->curr_block->preds[1]->block; + lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_); + lb_start_block(p, then); - LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2); + incoming_values[0] = lb_emit_conv(p, lhs, type).value; - return res; + lb_emit_jump(p, done); + lb_start_block(p, else_); + + incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, else_expr), type).value; + + lb_emit_jump(p, done); + lb_start_block(p, done); + + lbValue res = {}; + res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), ""); + res.type = type; + + GB_ASSERT(p->curr_block->preds.count >= 2); + incoming_blocks[0] = p->curr_block->preds[0]->block; + incoming_blocks[1] = p->curr_block->preds[1]->block; + + LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2); + + return res; + } } void lb_build_return_stmt(lbProcedure *p, Slice const &return_results); -- cgit v1.2.3 From 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/check_expr.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 7aee762f3afe4ff40f7365082d45a32f52328e74 Mon Sep 17 00:00:00 2001 From: Jasper Yujin Geer Date: Wed, 10 Aug 2022 17:39:21 -0700 Subject: Throw error when untyped shift expressions have non-integral type hints --- src/check_expr.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b2f3567ba..4dab26572 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2505,11 +2505,20 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ x->expr->tav.is_lhs = true; } x->mode = Addressing_Value; - if (type_hint && is_type_integer(type_hint)) { - x->type = type_hint; + if (type_hint) { + if (is_type_integer(type_hint)) { + x->type = type_hint; + } else { + gbString expr_str = expr_to_string(node); + gbString to_type = type_to_string(type_hint); + error(node, "Cannot convert untyped expression '%s' to '%s'", expr_str, to_type); + gb_string_free(expr_str); + gb_string_free(to_type); + x->mode = Addressing_Invalid; + return; + } } // x->value = x_val; - return; } } @@ -2522,7 +2531,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ // TODO(bill): Should we support shifts for fixed arrays and #simd vectors? if (!is_type_integer(x->type)) { - gbString err_str = expr_to_string(y->expr); + gbString err_str = expr_to_string(x->expr); error(node, "Shift operand '%s' must be an integer", err_str); gb_string_free(err_str); x->mode = Addressing_Invalid; -- cgit v1.2.3 From 5b621d5be18523939ded57cba24b3b3d19b774bd Mon Sep 17 00:00:00 2001 From: Jasper Yujin Geer Date: Wed, 10 Aug 2022 18:07:49 -0700 Subject: More accurate error message --- src/check_expr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 4dab26572..83bec20ae 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2509,10 +2509,10 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ if (is_type_integer(type_hint)) { x->type = type_hint; } else { - gbString expr_str = expr_to_string(node); + gbString x_str = expr_to_string(x->expr); gbString to_type = type_to_string(type_hint); - error(node, "Cannot convert untyped expression '%s' to '%s'", expr_str, to_type); - gb_string_free(expr_str); + error(node, "Conversion of shifted operand '%s' to '%s' is not allowed", x_str, to_type); + gb_string_free(x_str); gb_string_free(to_type); x->mode = Addressing_Invalid; return; -- cgit v1.2.3 From 57dd5ec4db2a8d4ea40a605a885e6a432d3ec568 Mon Sep 17 00:00:00 2001 From: Jasper Yujin Geer Date: Wed, 10 Aug 2022 18:25:29 -0700 Subject: Added back missing return statement --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 83bec20ae..f6c94466b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2515,10 +2515,10 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ gb_string_free(x_str); gb_string_free(to_type); x->mode = Addressing_Invalid; - return; } } // x->value = x_val; + return; } } -- cgit v1.2.3