From 8530829ca4609743c8acd947aea779fa51ea2c60 Mon Sep 17 00:00:00 2001 From: korvahkh <92224397+korvahkh@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:27:39 -0600 Subject: Fix dynamic array `index = value` with const `value` initializing to 0 --- src/llvm_backend_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 4675e203b..0c06c8c1b 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3657,7 +3657,7 @@ gb_internal void lb_build_addr_compound_lit_populate(lbProcedure *p, Slicekind == Ast_FieldValue) { ast_node(fv, FieldValue, elem); - if (lb_is_elem_const(fv->value, et)) { + if (bt->kind != Type_DynamicArray && lb_is_elem_const(fv->value, et)) { continue; } if (is_ast_range(fv->field)) { -- cgit v1.2.3 From 5a84a0822596fac47dd35bf1c2f1d9bb60bbe5c1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 17:24:42 +0000 Subject: Add general support for `bit_field`s --- base/runtime/internal.odin | 22 ++++++++++++ core/fmt/fmt.odin | 10 ++++-- src/check_expr.cpp | 86 ++++++++++++++++++++++++++++++++++++++------ src/check_stmt.cpp | 10 ++++++ src/check_type.cpp | 21 +++++++++-- src/checker.hpp | 1 + src/entity.cpp | 2 ++ src/llvm_backend.hpp | 8 +++++ src/llvm_backend_expr.cpp | 16 +++++++++ src/llvm_backend_general.cpp | 51 ++++++++++++++++++++++++-- src/parser.hpp | 1 + src/types.cpp | 34 ++++++++++++++++++ 12 files changed, 245 insertions(+), 17 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/base/runtime/internal.odin b/base/runtime/internal.odin index 691f76ff1..62bee8620 100644 --- a/base/runtime/internal.odin +++ b/base/runtime/internal.odin @@ -1034,3 +1034,25 @@ fixdfti :: proc(a: u64) -> i128 { } } + + + +__write_bits :: proc "contextless" (dst, src: [^]byte, offset: uintptr, size: uintptr) { + for i in 0..value.kind == ExactValue_Integer) { gbString b = type_to_string(type); i64 sz = type_size_of(type); + i64 bit_size = 8*sz; + bool size_changed = false; + if (max_bit_size > 0) { + size_changed = (bit_size != max_bit_size); + bit_size = gb_min(bit_size, max_bit_size); + } BigInt *bi = &o->value.value_integer; if (is_type_unsigned(type)) { if (big_int_is_neg(bi)) { @@ -2083,25 +2089,36 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, } else { BigInt one = big_int_make_u64(1); BigInt max_size = big_int_make_u64(1); - BigInt bits = big_int_make_i64(8*sz); + BigInt bits = big_int_make_i64(bit_size); big_int_shl_eq(&max_size, &bits); big_int_sub_eq(&max_size, &one); String max_size_str = big_int_to_string(temporary_allocator(), &max_size); - error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + + if (size_changed) { + error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %u' is '%.*s'\n", b, bit_size, LIT(max_size_str)); + } else { + error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + } } } else { BigInt zero = big_int_make_u64(0); BigInt one = big_int_make_u64(1); BigInt max_size = big_int_make_u64(1); - BigInt bits = big_int_make_i64(8*sz - 1); + BigInt bits = big_int_make_i64(bit_size - 1); big_int_shl_eq(&max_size, &bits); + + String max_size_str = {}; if (big_int_is_neg(bi)) { big_int_neg(&max_size, &max_size); - String max_size_str = big_int_to_string(temporary_allocator(), &max_size); - error_line("\tThe minimum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + max_size_str = big_int_to_string(temporary_allocator(), &max_size); } else { big_int_sub_eq(&max_size, &one); - String max_size_str = big_int_to_string(temporary_allocator(), &max_size); + max_size_str = big_int_to_string(temporary_allocator(), &max_size); + } + + if (size_changed) { + error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %u' is '%.*s'\n", b, bit_size, LIT(max_size_str)); + } else { error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); } } @@ -2112,7 +2129,7 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, } return false; } -gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type) { +gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type, i64 max_bit_size) { gbString a = expr_to_string(o->expr); gbString b = type_to_string(type); defer( @@ -2143,7 +2160,7 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o error_line("\t whereas slices in general are assumed to be mutable.\n"); } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) { error_line("\tSuggestion: the expression may be casted to %s\n", b); - } else if (check_integer_exceed_suggestion(c, o, type)) { + } else if (check_integer_exceed_suggestion(c, o, type, max_bit_size)) { return; } } @@ -2217,13 +2234,18 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ if (!is_type_integer(o->type) && is_type_integer(type)) { error(o->expr, "'%s' truncated to '%s', got %s", a, b, s); } else { + i64 max_bit_size = 0; + if (ctx->bit_field_bit_size) { + max_bit_size = ctx->bit_field_bit_size; + } + if (are_types_identical(o->type, type)) { error(o->expr, "Numeric value '%s' from '%s' cannot be represented by '%s'", s, a, b); } else { error(o->expr, "Cannot convert numeric value '%s' from '%s' to '%s' from '%s'", s, a, b, c); } - check_assignment_error_suggestion(ctx, o, type); + check_assignment_error_suggestion(ctx, o, type, max_bit_size); } } else { error(o->expr, "Cannot convert '%s' to '%s' from '%s', got %s", a, b, c, s); @@ -2234,6 +2256,11 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ } gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { + if (o->expr && o->expr->kind == Ast_SelectorExpr) { + if (o->expr->SelectorExpr.is_bit_field) { + return true; + } + } if (o->mode == Addressing_OptionalOk) { Ast *expr = unselector_expr(o->expr); if (expr->kind != Ast_TypeAssertion) { @@ -2306,6 +2333,8 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * Entity *e = entity_of_node(ue->expr); if (e != nullptr && (e->flags & EntityFlag_Param) != 0) { error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str); + } else if (e != nullptr && (e->flags & EntityFlag_BitFieldField) != 0) { + error(op, "Cannot take the pointer address of '%s' which is a bit_field's field", str); } else { switch (o->mode) { case Addressing_Constant: @@ -5067,6 +5096,11 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod operand->type = entity->type; operand->expr = node; + if (entity->flags & EntityFlag_BitFieldField) { + add_package_dependency(c, "runtime", "__write_bits"); + add_package_dependency(c, "runtime", "__read_bits"); + } + switch (entity->kind) { case Entity_Constant: operand->value = entity->Constant.value; @@ -5080,6 +5114,9 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } break; case Entity_Variable: + if (sel.is_bit_field) { + se->is_bit_field = true; + } if (sel.indirect) { operand->mode = Addressing_Variable; } else if (operand->mode == Addressing_Context) { @@ -11115,6 +11152,33 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan case_end; + case_ast_node(f, BitFieldField, node); + str = write_expr_to_string(str, f->name, shorthand); + str = gb_string_appendc(str, ": "); + str = write_expr_to_string(str, f->type, shorthand); + str = gb_string_appendc(str, " | "); + str = write_expr_to_string(str, f->bit_size, shorthand); + case_end; + case_ast_node(bf, BitFieldType, node); + str = gb_string_appendc(str, "bit_field "); + if (!shorthand) { + str = write_expr_to_string(str, bf->backing_type, shorthand); + } + str = gb_string_appendc(str, " {"); + if (shorthand) { + str = gb_string_appendc(str, "..."); + } else { + for_array(i, bf->fields) { + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = write_expr_to_string(str, bf->fields[i], false); + } + return str; + } + str = gb_string_appendc(str, "}"); + case_end; + case_ast_node(ia, InlineAsmExpr, node); str = gb_string_appendc(str, "asm("); for_array(i, ia->param_types) { diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 6897701d6..a7dd9743b 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -485,7 +485,17 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O } } + Entity *lhs_e = entity_of_node(lhs->expr); + u8 prev_bit_field_bit_size = ctx->bit_field_bit_size; + if (lhs_e && lhs_e->kind == Entity_Variable && lhs_e->Variable.bit_field_bit_size) { + // HACK NOTE(bill): This is a bit of a hack, but it will work fine for this use case + ctx->bit_field_bit_size = lhs_e->Variable.bit_field_bit_size; + } + check_assignment(ctx, rhs, assignment_type, str_lit("assignment")); + + ctx->bit_field_bit_size = prev_bit_field_bit_size; + if (rhs->mode == Addressing_Invalid) { return nullptr; } diff --git a/src/check_type.cpp b/src/check_type.cpp index 8afac2fc5..8c746a2f7 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1035,11 +1035,19 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, error(f->bit_size, "A bit_field's specified bit size cannot exceed 64 bits, got %lld", cast(long long)bit_size_i64); bit_size_i64 = 64; } + i64 sz = 8*type_size_of(type); + if (bit_size_i64 > sz) { + error(f->bit_size, "A bit_field's specified bit size cannot exceed its type, got %lld, expect <=%lld", cast(long long)bit_size_i64, cast(long long)sz); + bit_size_i64 = sz; + } + bit_size_u8 = cast(u8)bit_size_i64; Entity *e = alloc_entity_field(ctx->scope, f->name->Ident.token, type, false, field_src_index); e->Variable.docs = docs; e->Variable.comment = comment; + e->Variable.bit_field_bit_size = bit_size_u8; + e->flags |= EntityFlag_BitFieldField; add_entity(ctx, ctx->scope, nullptr, e); array_add(&fields, e); @@ -1050,6 +1058,14 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, GB_ASSERT(fields.count <= bf->fields.count); + auto bit_offsets = slice_make(permanent_allocator(), fields.count); + i64 curr_offset = 0; + for_array(i, bit_sizes) { + bit_offsets[i] = curr_offset; + curr_offset += cast(i64)bit_sizes[i]; + } + + if (total_bit_size > maximum_bit_size) { gbString s = type_to_string(backing_type); error(node, "The numbers required %llu exceeds the backing type's (%s) bit size %llu", @@ -1059,8 +1075,9 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, gb_string_free(s); } - bit_field_type->BitField.fields = slice_from_array(fields); - bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes); + bit_field_type->BitField.fields = slice_from_array(fields); + bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes); + bit_field_type->BitField.bit_offsets = bit_offsets; } gb_internal bool is_type_valid_bit_set_range(Type *t) { diff --git a/src/checker.hpp b/src/checker.hpp index 9aee82257..066d6bb4a 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -475,6 +475,7 @@ struct CheckerContext { bool hide_polymorphic_errors; bool in_polymorphic_specialization; bool allow_arrow_right_selector_expr; + u8 bit_field_bit_size; Scope * polymorphic_scope; Ast *assignment_lhs_hint; diff --git a/src/entity.cpp b/src/entity.cpp index e6c46d37e..916c2b2bd 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -43,6 +43,7 @@ enum EntityFlag : u64 { EntityFlag_NoAlias = 1ull<<9, EntityFlag_TypeField = 1ull<<10, EntityFlag_Value = 1ull<<11, + EntityFlag_BitFieldField = 1ull<<12, @@ -212,6 +213,7 @@ struct Entity { Ast *init_expr; // only used for some variables within procedure bodies i32 field_index; i32 field_group_index; + u8 bit_field_bit_size; ParameterValue param_value; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 026454c81..00d1b7a21 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -84,6 +84,8 @@ enum lbAddrKind { lbAddr_Swizzle, lbAddr_SwizzleLarge, + + lbAddr_BitField, }; struct lbAddr { @@ -118,6 +120,12 @@ struct lbAddr { Type *type; Slice indices; } swizzle_large; + struct { + Type *type; + i64 index; + i64 bit_offset; + i64 bit_size; + } bitfield; }; }; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 0c06c8c1b..6bef21822 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4627,6 +4627,22 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { Selection sel = lookup_field(type, selector, false); GB_ASSERT(sel.entity != nullptr); + if (sel.is_bit_field) { + lbAddr addr = lb_build_addr(p, se->expr); + Type *bf_type = base_type(type_deref(lb_addr_type(addr))); + GB_ASSERT(bf_type->kind == Type_BitField); + + lbValue a = lb_addr_get_ptr(p, addr); + Selection sub_sel = sel; + sub_sel.index.count -= 1; + i32 index = sel.index[sel.index.count-1]; + + Entity *f = bf_type->BitField.fields[index]; + u8 bit_size = bf_type->BitField.bit_sizes[index]; + i64 bit_offset = bf_type->BitField.bit_offsets[index]; + + return lb_addr_bit_field(a, f->type, index, bit_offset, bit_size); + } if (sel.pseudo_field) { GB_ASSERT(sel.entity->kind == Entity_Procedure || sel.entity->kind == Entity_ProcGroup); Entity *e = entity_of_node(sel_node); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 2102420f8..4ff8482a7 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -451,6 +451,20 @@ gb_internal lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slice(temporary_allocator(), 4); + args[0] = dst; + args[1] = lb_address_from_load_or_generate_local(p, value); + args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset); + args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size); + lb_emit_runtime_call(p, "__write_bits", args); + return; + } else if (addr.kind == lbAddr_RelativePointer) { Type *rel_ptr = base_type(lb_addr_type(addr)); GB_ASSERT(rel_ptr->kind == Type_RelativePointer || rel_ptr->kind == Type_RelativeMultiPointer); @@ -1074,8 +1098,31 @@ gb_internal lbValue lb_emit_load(lbProcedure *p, lbValue value) { gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { GB_ASSERT(addr.addr.value != nullptr); + if (addr.kind == lbAddr_BitField) { + lbAddr dst = lb_add_local_generated(p, addr.bitfield.type, true); + lbValue src = addr.addr; - if (addr.kind == lbAddr_RelativePointer) { + auto args = array_make(temporary_allocator(), 4); + args[0] = dst.addr; + args[1] = src; + args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset); + args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size); + lb_emit_runtime_call(p, "__read_bits", args); + + lbValue r = lb_addr_load(p, dst); + + if (!is_type_unsigned(core_type(addr.bitfield.type))) { + // Sign extension + // m := 1<<(bit_size-1) + // r = (r XOR m) - m + Type *t = addr.bitfield.type; + lbValue m = lb_const_int(p->module, t, 1ull<<(addr.bitfield.bit_size-1)); + r = lb_emit_arith(p, Token_Xor, r, m, t); + r = lb_emit_arith(p, Token_Sub, r, m, t); + } + + return r; + } else if (addr.kind == lbAddr_RelativePointer) { Type *rel_ptr = base_type(lb_addr_type(addr)); Type *base_integer = nullptr; Type *pointer_type = nullptr; diff --git a/src/parser.hpp b/src/parser.hpp index ff77c88c7..1f4ec8726 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -429,6 +429,7 @@ AST_KIND(_ExprBegin, "", bool) \ Ast *expr, *selector; \ u8 swizzle_count; /*maximum of 4 components, if set, count >= 2*/ \ u8 swizzle_indices; /*2 bits per component*/ \ + bool is_bit_field; \ }) \ AST_KIND(ImplicitSelectorExpr, "implicit selector expression", struct { Token token; Ast *selector; }) \ AST_KIND(SelectorCallExpr, "selector call expression", struct { \ diff --git a/src/types.cpp b/src/types.cpp index 1c28e6583..be4b8944b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -287,6 +287,7 @@ struct TypeProc { Type * backing_type; \ Slice fields; \ Slice bit_sizes; \ + Slice bit_offsets; \ Ast * node; \ }) \ TYPE_KIND(SoaPointer, struct { Type *elem; }) @@ -408,6 +409,7 @@ struct Selection { bool indirect; // Set if there was a pointer deref anywhere down the line u8 swizzle_count; // maximum components = 4 u8 swizzle_indices; // 2 bits per component, representing which swizzle index + bool is_bit_field; bool pseudo_field; }; gb_global Selection const empty_selection = {0}; @@ -3187,6 +3189,21 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name 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]; + if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) { + continue; + } + String str = f->token.string; + if (field_name == str) { + selection_add_index(&sel, i); // HACK(bill): Leaky memory + sel.entity = f; + sel.is_bit_field = true; + return sel; + } + } + } else if (type->kind == Type_Basic) { switch (type->Basic.kind) { case Basic_any: { @@ -4551,6 +4568,23 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_appendc(str, gb_bprintf("matrix[%d, %d]", cast(int)type->Matrix.row_count, cast(int)type->Matrix.column_count)); str = write_type_to_string(str, type->Matrix.elem); break; + + case Type_BitField: + str = gb_string_appendc(str, "bit_field "); + str = write_type_to_string(str, type->BitField.backing_type); + str = gb_string_appendc(str, " {"); + for (isize i = 0; i < type->BitField.fields.count; i++) { + Entity *f = type->BitField.fields[i]; + if (i > 0) { + str = gb_string_appendc(str, ", "); + } + str = gb_string_append_length(str, f->token.string.text, f->token.string.len); + str = gb_string_appendc(str, ": "); + str = write_type_to_string(str, f->type); + str = gb_string_append_fmt(str, " | %u", type->BitField.bit_sizes[i]); + } + str = gb_string_appendc(str, " }"); + break; } return str; -- cgit v1.2.3 From 5f001f6d5138d61fbb4900c951e2ccb12894d5ed Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 18:15:13 +0000 Subject: Allow casting between a `bit_field` and its backing type --- src/check_decl.cpp | 1 + src/check_expr.cpp | 7 +++++++ src/llvm_backend_expr.cpp | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 3ccf1b97a..2c0f7a7b8 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -210,6 +210,7 @@ gb_internal bool is_type_distinct(Ast *node) { case Ast_UnionType: case Ast_EnumType: case Ast_ProcType: + case Ast_BitFieldType: return true; case Ast_PointerType: diff --git a/src/check_expr.cpp b/src/check_expr.cpp index aba2f5831..792e5b43c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2908,6 +2908,13 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type } } + if (is_type_bit_field(src)) { + return are_types_identical(core_type(src->BitField.backing_type), dst); + } + if (is_type_bit_field(dst)) { + return are_types_identical(src, core_type(dst->BitField.backing_type)); + } + if (is_type_integer(src) && is_type_rune(dst)) { return true; } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 6bef21822..7b31ca989 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1946,6 +1946,24 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } } + // bit_field <-> backing type + if (is_type_bit_field(src)) { + if (are_types_identical(src->BitField.backing_type, dst)) { + lbValue res = {}; + res.type = t; + res.value = value.value; + return res; + } + } + if (is_type_bit_field(dst)) { + if (are_types_identical(src, dst->BitField.backing_type)) { + lbValue res = {}; + res.type = t; + res.value = value.value; + return res; + } + } + // Pointer <-> uintptr if (is_type_pointer(src) && is_type_uintptr(dst)) { -- cgit v1.2.3 From afcc2889ecf532e03878825d7eb713674d1e7af7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 18:41:15 +0000 Subject: Support compound literals for `bit_field` --- core/odin/doc-format/doc_format.odin | 2 +- src/check_expr.cpp | 49 ++++++++++++++++++++++++++++++++---- src/llvm_backend_expr.cpp | 32 +++++++++++++++++++++++ 3 files changed, 77 insertions(+), 6 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index ebc05c4dc..5636b1059 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -139,7 +139,7 @@ Entity :: struct { // May be used by (Struct fields and procedure fields): // .Variable // .Constant - // This is equal to the "bit size" it this is a `bit_field`s field + // This is equal to the negative of the "bit size" it this is a `bit_field`s field field_group_index: i32le, // May used by: diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 792e5b43c..d5890b191 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8440,6 +8440,11 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice fields_visited_through_raw_union = {}; defer (string_map_destroy(&fields_visited_through_raw_union)); + String assignment_str = str_lit("structure literal"); + if (bt->kind == Type_BitField) { + assignment_str = str_lit("bit_field literal"); + } + for (Ast *elem : elems) { if (elem->kind != Ast_FieldValue) { error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); @@ -8461,17 +8466,26 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, SliceStruct.fields[sel.index[0]]; + Entity *field = nullptr; + if (bt->kind == Type_Struct) { + field = bt->Struct.fields[sel.index[0]]; + } else if (bt->kind == Type_BitField) { + field = bt->BitField.fields[sel.index[0]]; + } else { + GB_PANIC("Unknown type"); + } + + add_entity_use(c, fv->field, field); if (string_set_update(&fields_visited, name)) { if (sel.index.count > 1) { if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found)); } else { - error(fv->field, "Duplicate or reused field '%.*s' in structure literal", LIT(sel.entity->token.string)); + error(fv->field, "Duplicate or reused field '%.*s' in %.*s", LIT(sel.entity->token.string), LIT(assignment_str)); } } else { - error(fv->field, "Duplicate field '%.*s' in structure literal", LIT(field->token.string)); + error(fv->field, "Duplicate field '%.*s' in %.*s", LIT(field->token.string), LIT(assignment_str)); } continue; } else if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { @@ -8479,11 +8493,13 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slicefield, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a structure literal", cast(int)sel.index.count-1, LIT(name)); + error(fv->field, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a %.*s", cast(int)sel.index.count-1, LIT(name), LIT(assignment_str)); continue; } if (sel.index.count > 1) { + GB_ASSERT(bt->kind == Type_Struct); + if (is_constant) { Type *ft = type; for (i32 index : sel.index) { @@ -8544,7 +8560,15 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slicetype, str_lit("structure literal")); + u8 prev_bit_field_bit_size = c->bit_field_bit_size; + if (field->kind == Entity_Variable && field->Variable.bit_field_bit_size) { + // HACK NOTE(bill): This is a bit of a hack, but it will work fine for this use case + c->bit_field_bit_size = field->Variable.bit_field_bit_size; + } + + check_assignment(c, &o, field->type, assignment_str); + + c->bit_field_bit_size = prev_bit_field_bit_size; } } @@ -9346,6 +9370,21 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } break; } + case Type_BitField: { + if (cl->elems.count == 0) { + break; // NOTE(bill): No need to init + } + is_constant = false; + if (cl->elems[0]->kind != Ast_FieldValue) { + gbString type_str = type_to_string(type); + error(node, "%s ('bit_field') compound literals are only allowed to contain 'field = value' elements", type_str); + gb_string_free(type_str); + } else { + check_compound_literal_field_values(c, cl->elems, o, type, is_constant); + } + break; + } + default: { if (cl->elems.count == 0) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 7b31ca989..7e000c9e8 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4235,6 +4235,38 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { switch (bt->kind) { default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break; + case Type_BitField: + for (Ast *elem : cl->elems) { + ast_node(fv, FieldValue, elem); + String name = fv->field->Ident.token.string; + Selection sel = lookup_field(bt, name, false); + GB_ASSERT(sel.is_bit_field); + GB_ASSERT(!sel.indirect); + GB_ASSERT(sel.index.count == 1); + GB_ASSERT(sel.entity != nullptr); + + i64 index = sel.index[0]; + i64 bit_offset = 0; + i64 bit_size = -1; + for_array(i, bt->BitField.fields) { + Entity *f = bt->BitField.fields[i]; + if (f == sel.entity) { + bit_offset = bt->BitField.bit_offsets[i]; + bit_size = bt->BitField.bit_sizes[i]; + break; + } + } + GB_ASSERT(bit_size > 0); + + Type *field_type = sel.entity->type; + lbValue field_expr = lb_build_expr(p, fv->value); + field_expr = lb_emit_conv(p, field_expr, field_type); + + lbAddr field_addr = lb_addr_bit_field(v.addr, field_type, index, bit_offset, bit_size); + lb_addr_store(p, field_addr, field_expr); + } + return v; + 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 -- cgit v1.2.3 From c14b9d461a5c58d4b80957682f00205714063435 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 19:14:16 +0000 Subject: Support `using` of a `bit_field` within a `struct` --- src/check_type.cpp | 2 ++ src/llvm_backend_expr.cpp | 14 +++++++-- src/llvm_backend_utility.cpp | 2 +- src/types.cpp | 71 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 83 insertions(+), 6 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 41eae2178..74828f97f 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -89,6 +89,8 @@ gb_internal bool does_field_type_allow_using(Type *t) { return true; } else if (is_type_array(t)) { return t->Array.count <= 4; + } else if (is_type_bit_field(t)) { + return true; } return false; } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 7e000c9e8..5bf2642e6 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4679,12 +4679,20 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT(sel.entity != nullptr); if (sel.is_bit_field) { lbAddr addr = lb_build_addr(p, se->expr); - Type *bf_type = base_type(type_deref(lb_addr_type(addr))); - GB_ASSERT(bf_type->kind == Type_BitField); - lbValue a = lb_addr_get_ptr(p, addr); + Selection sub_sel = sel; sub_sel.index.count -= 1; + + Type *bf_type = type_from_selection(type, sub_sel); + bf_type = base_type(type_deref(bf_type)); + GB_ASSERT(bf_type->kind == Type_BitField); + + lbValue a = lb_addr_get_ptr(p, addr); + if (sub_sel.index.count > 0) { + a = lb_emit_deep_field_gep(p, a, sub_sel); + } + i32 index = sel.index[sel.index.count-1]; Entity *f = bf_type->BitField.fields[index]; diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index bc5106601..5bd3cd8e2 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1332,7 +1332,7 @@ gb_internal lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection if (index == 0) { type = t_rawptr; } else if (index == 1) { - type = t_type_info_ptr; + type = t_typeid; } e = lb_emit_struct_ep(p, e, index); break; diff --git a/src/types.cpp b/src/types.cpp index be4b8944b..3945c7111 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -385,6 +385,9 @@ enum : int { gb_internal bool is_type_comparable(Type *t); gb_internal bool is_type_simple_compare(Type *t); +gb_internal Type *type_deref(Type *t, bool allow_multi_pointer=false); +gb_internal Type *base_type(Type *t); +gb_internal Type *alloc_type_multi_pointer(Type *elem); gb_internal u32 type_info_flags_of_type(Type *type) { if (type == nullptr) { @@ -762,7 +765,6 @@ gb_internal bool is_type_proc(Type *t); gb_internal bool is_type_slice(Type *t); gb_internal bool is_type_integer(Type *t); gb_internal bool type_set_offsets(Type *t); -gb_internal Type *base_type(Type *t); gb_internal i64 type_size_of_internal(Type *t, TypePath *path); gb_internal i64 type_align_of_internal(Type *t, TypePath *path); @@ -1157,7 +1159,7 @@ gb_internal Type *alloc_type_simd_vector(i64 count, Type *elem, Type *generic_co //////////////////////////////////////////////////////////////// -gb_internal Type *type_deref(Type *t, bool allow_multi_pointer=false) { +gb_internal Type *type_deref(Type *t, bool allow_multi_pointer) { if (t != nullptr) { Type *bt = base_type(t); if (bt == nullptr) { @@ -4261,6 +4263,71 @@ gb_internal Type *alloc_type_proc_from_types(Type **param_types, unsigned param_ } +gb_internal Type *type_from_selection(Type *type, Selection const &sel) { + for (i32 index : sel.index) { + Type *bt = base_type(type_deref(type)); + switch (bt->kind) { + case Type_Struct: + type = bt->Struct.fields[index]->type; + break; + case Type_Tuple: + type = bt->Tuple.variables[index]->type; + break; + case Type_BitField: + type = bt->BitField.fields[index]->type; + break; + case Type_Array: + type = bt->Array.elem; + break; + case Type_EnumeratedArray: + type = bt->Array.elem; + break; + case Type_Slice: + switch (index) { + case 0: type = alloc_type_multi_pointer(bt->Slice.elem); break; + case 1: type = t_int; break; + } + break; + case Type_DynamicArray: + switch (index) { + case 0: type = alloc_type_multi_pointer(bt->DynamicArray.elem); break; + case 1: type = t_int; break; + case 2: type = t_int; break; + case 3: type = t_allocator; break; + } + break; + case Type_Map: + switch (index) { + case 0: type = t_uintptr; break; + case 1: type = t_int; break; + case 2: type = t_allocator; break; + } + break; + case Type_Basic: + if (is_type_complex_or_quaternion(bt)) { + type = base_complex_elem_type(bt); + } else { + switch (type->Basic.kind) { + case Basic_any: + switch (index) { + case 0: type = t_rawptr; break; + case 1: type = t_typeid; break; + } + break; + case Basic_string: + switch (index) { + case 0: type = t_u8_multi_ptr; break; + case 1: type = t_int; break; + } + break; + } + } + break; + } + } + return type; +} + gb_internal gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) { if (type == nullptr) { -- cgit v1.2.3 From 3060225f460cb5d1ad124fcf449b27b3e2e981f8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 19:24:16 +0000 Subject: Simplify usage code --- src/llvm_backend_expr.cpp | 8 +-- src/types.cpp | 130 +++++++++++++++++++++++----------------------- 2 files changed, 69 insertions(+), 69 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 5bf2642e6..442121f83 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4684,15 +4684,17 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { Selection sub_sel = sel; sub_sel.index.count -= 1; - Type *bf_type = type_from_selection(type, sub_sel); - bf_type = base_type(type_deref(bf_type)); - GB_ASSERT(bf_type->kind == Type_BitField); lbValue a = lb_addr_get_ptr(p, addr); if (sub_sel.index.count > 0) { a = lb_emit_deep_field_gep(p, a, sub_sel); } + + Type *bf_type = type_deref(a.type); + bf_type = base_type(type_deref(bf_type)); + GB_ASSERT(bf_type->kind == Type_BitField); + i32 index = sel.index[sel.index.count-1]; Entity *f = bf_type->BitField.fields[index]; diff --git a/src/types.cpp b/src/types.cpp index 3945c7111..eac834f25 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -4262,72 +4262,70 @@ gb_internal Type *alloc_type_proc_from_types(Type **param_types, unsigned param_ return t; } - -gb_internal Type *type_from_selection(Type *type, Selection const &sel) { - for (i32 index : sel.index) { - Type *bt = base_type(type_deref(type)); - switch (bt->kind) { - case Type_Struct: - type = bt->Struct.fields[index]->type; - break; - case Type_Tuple: - type = bt->Tuple.variables[index]->type; - break; - case Type_BitField: - type = bt->BitField.fields[index]->type; - break; - case Type_Array: - type = bt->Array.elem; - break; - case Type_EnumeratedArray: - type = bt->Array.elem; - break; - case Type_Slice: - switch (index) { - case 0: type = alloc_type_multi_pointer(bt->Slice.elem); break; - case 1: type = t_int; break; - } - break; - case Type_DynamicArray: - switch (index) { - case 0: type = alloc_type_multi_pointer(bt->DynamicArray.elem); break; - case 1: type = t_int; break; - case 2: type = t_int; break; - case 3: type = t_allocator; break; - } - break; - case Type_Map: - switch (index) { - case 0: type = t_uintptr; break; - case 1: type = t_int; break; - case 2: type = t_allocator; break; - } - break; - case Type_Basic: - if (is_type_complex_or_quaternion(bt)) { - type = base_complex_elem_type(bt); - } else { - switch (type->Basic.kind) { - case Basic_any: - switch (index) { - case 0: type = t_rawptr; break; - case 1: type = t_typeid; break; - } - break; - case Basic_string: - switch (index) { - case 0: type = t_u8_multi_ptr; break; - case 1: type = t_int; break; - } - break; - } - } - break; - } - } - return type; -} - +// gb_internal Type *type_from_selection(Type *type, Selection const &sel) { +// for (i32 index : sel.index) { +// Type *bt = base_type(type_deref(type)); +// switch (bt->kind) { +// case Type_Struct: +// type = bt->Struct.fields[index]->type; +// break; +// case Type_Tuple: +// type = bt->Tuple.variables[index]->type; +// break; +// case Type_BitField: +// type = bt->BitField.fields[index]->type; +// break; +// case Type_Array: +// type = bt->Array.elem; +// break; +// case Type_EnumeratedArray: +// type = bt->Array.elem; +// break; +// case Type_Slice: +// switch (index) { +// case 0: type = alloc_type_multi_pointer(bt->Slice.elem); break; +// case 1: type = t_int; break; +// } +// break; +// case Type_DynamicArray: +// switch (index) { +// case 0: type = alloc_type_multi_pointer(bt->DynamicArray.elem); break; +// case 1: type = t_int; break; +// case 2: type = t_int; break; +// case 3: type = t_allocator; break; +// } +// break; +// case Type_Map: +// switch (index) { +// case 0: type = t_uintptr; break; +// case 1: type = t_int; break; +// case 2: type = t_allocator; break; +// } +// break; +// case Type_Basic: +// if (is_type_complex_or_quaternion(bt)) { +// type = base_complex_elem_type(bt); +// } else { +// switch (type->Basic.kind) { +// case Basic_any: +// switch (index) { +// case 0: type = t_rawptr; break; +// case 1: type = t_typeid; break; +// } +// break; +// case Basic_string: +// switch (index) { +// case 0: type = t_u8_multi_ptr; break; +// case 1: type = t_int; break; +// } +// break; +// } +// } +// break; +// } +// } +// return type; +// } gb_internal gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) { if (type == nullptr) { -- cgit v1.2.3 From e127d21fedbcd5600d8bd1faf2dec40f3767658e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 19:24:50 +0000 Subject: Check for pseudo-fields before bit fields --- src/llvm_backend_expr.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 442121f83..a6f4a5752 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4677,6 +4677,13 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { Selection sel = lookup_field(type, selector, false); GB_ASSERT(sel.entity != nullptr); + if (sel.pseudo_field) { + GB_ASSERT(sel.entity->kind == Entity_Procedure || sel.entity->kind == Entity_ProcGroup); + Entity *e = entity_of_node(sel_node); + GB_ASSERT(e->kind == Entity_Procedure); + return lb_addr(lb_find_value_from_entity(p->module, e)); + } + if (sel.is_bit_field) { lbAddr addr = lb_build_addr(p, se->expr); @@ -4703,12 +4710,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { return lb_addr_bit_field(a, f->type, index, bit_offset, bit_size); } - if (sel.pseudo_field) { - GB_ASSERT(sel.entity->kind == Entity_Procedure || sel.entity->kind == Entity_ProcGroup); - Entity *e = entity_of_node(sel_node); - GB_ASSERT(e->kind == Entity_Procedure); - return lb_addr(lb_find_value_from_entity(p->module, e)); - } + { lbAddr addr = lb_build_addr(p, se->expr); -- cgit v1.2.3 From 3f193d7446c971175dd7a27154af1068767034bc Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Feb 2024 19:27:13 +0000 Subject: Format change --- src/llvm_backend_expr.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index a6f4a5752..5bc961af2 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4687,18 +4687,15 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { if (sel.is_bit_field) { lbAddr addr = lb_build_addr(p, se->expr); - Selection sub_sel = sel; sub_sel.index.count -= 1; - - lbValue a = lb_addr_get_ptr(p, addr); + lbValue ptr = lb_addr_get_ptr(p, addr); if (sub_sel.index.count > 0) { - a = lb_emit_deep_field_gep(p, a, sub_sel); + ptr = lb_emit_deep_field_gep(p, ptr, sub_sel); } - - Type *bf_type = type_deref(a.type); + Type *bf_type = type_deref(ptr.type); bf_type = base_type(type_deref(bf_type)); GB_ASSERT(bf_type->kind == Type_BitField); @@ -4708,10 +4705,9 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { u8 bit_size = bf_type->BitField.bit_sizes[index]; i64 bit_offset = bf_type->BitField.bit_offsets[index]; - return lb_addr_bit_field(a, f->type, index, bit_offset, bit_size); + return lb_addr_bit_field(ptr, f->type, index, bit_offset, bit_size); } - { lbAddr addr = lb_build_addr(p, se->expr); if (addr.kind == lbAddr_Map) { -- cgit v1.2.3 From c7c68520577133d6332bd6df98c44e751b571c03 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 12 Mar 2024 12:11:48 +0000 Subject: Support swizzle selector syntax `.xyzw` for `#simd` vectors --- src/check_expr.cpp | 13 +++++--- src/llvm_backend_expr.cpp | 4 +-- src/llvm_backend_general.cpp | 26 +++++++++++++++- src/types.cpp | 71 ++++++++++++++++++++++++++++---------------- 4 files changed, 82 insertions(+), 32 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3a8cdf0b1..0911e48cf 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4920,7 +4920,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } } - if (entity == nullptr && selector->kind == Ast_Ident && is_type_array(type_deref(operand->type))) { + if (entity == nullptr && selector->kind == Ast_Ident && (is_type_array(type_deref(operand->type)) || is_type_simd_vector(type_deref(operand->type)))) { String field_name = selector->Ident.token.string; if (1 < field_name.len && field_name.len <= 4) { u8 swizzles_xyzw[4] = {'x', 'y', 'z', 'w'}; @@ -4975,8 +4975,10 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod Type *original_type = operand->type; Type *array_type = base_type(type_deref(original_type)); - GB_ASSERT(array_type->kind == Type_Array); - i64 array_count = array_type->Array.count; + GB_ASSERT(array_type->kind == Type_Array || array_type->kind == Type_SimdVector); + + i64 array_count = get_array_type_count(array_type); + for (u8 i = 0; i < index_count; i++) { u8 idx = indices>>(i*2) & 3; if (idx >= array_count) { @@ -4996,7 +4998,6 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod se->swizzle_count = index_count; se->swizzle_indices = indices; - AddressingMode prev_mode = operand->mode; operand->mode = Addressing_SwizzleValue; operand->type = determine_swizzle_array_type(original_type, type_hint, index_count); @@ -5010,6 +5011,10 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod break; } + if (array_type->kind == Type_SimdVector) { + operand->mode = Addressing_Value; + } + Entity *swizzle_entity = alloc_entity_variable(nullptr, make_token_ident(field_name), operand->type, EntityState_Resolved); add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); return swizzle_entity; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 5bc961af2..98618798b 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4655,7 +4655,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { if (se->swizzle_count > 0) { Type *array_type = base_type(type_deref(tav.type)); - GB_ASSERT(array_type->kind == Type_Array); + GB_ASSERT(array_type->kind == Type_Array || array_type->kind == Type_SimdVector); u8 swizzle_count = se->swizzle_count; u8 swizzle_indices_raw = se->swizzle_indices; u8 swizzle_indices[4] = {}; @@ -4671,7 +4671,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { a = lb_addr_get_ptr(p, addr); } - GB_ASSERT(is_type_array(expr->tav.type)); + GB_ASSERT(is_type_array(expr->tav.type) || is_type_simd_vector(expr->tav.type)); return lb_addr_swizzle(a, expr->tav.type, swizzle_count, swizzle_indices); } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 4ff8482a7..09de90dc9 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -434,7 +434,7 @@ gb_internal lbAddr lb_addr_soa_variable(lbValue addr, lbValue index, Ast *index_ } gb_internal lbAddr lb_addr_swizzle(lbValue addr, Type *array_type, u8 swizzle_count, u8 swizzle_indices[4]) { - GB_ASSERT(is_type_array(array_type)); + GB_ASSERT(is_type_array(array_type) || is_type_simd_vector(array_type)); GB_ASSERT(1 < swizzle_count && swizzle_count <= 4); lbAddr v = {lbAddr_Swizzle, addr}; v.swizzle.type = array_type; @@ -1264,6 +1264,30 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { return lb_addr_load(p, res); } else if (addr.kind == lbAddr_Swizzle) { Type *array_type = base_type(addr.swizzle.type); + if (array_type->kind == Type_SimdVector) { + lbValue vec = lb_emit_load(p, addr.addr); + u8 index_count = addr.swizzle.count; + if (index_count == 0) { + return vec; + } + + unsigned mask_len = cast(unsigned)index_count; + LLVMValueRef *mask_elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, index_count); + for (isize i = 0; i < index_count; i++) { + mask_elems[i] = LLVMConstInt(lb_type(p->module, t_u32), addr.swizzle.indices[i], false); + } + + LLVMValueRef mask = LLVMConstVector(mask_elems, mask_len); + + LLVMValueRef v1 = vec.value; + LLVMValueRef v2 = vec.value; + + lbValue res = {}; + res.type = addr.swizzle.type; + res.value = LLVMBuildShuffleVector(p->builder, v1, v2, mask, ""); + return res; + } + GB_ASSERT(array_type->kind == Type_Array); unsigned res_align = cast(unsigned)type_align_of(addr.swizzle.type); diff --git a/src/types.cpp b/src/types.cpp index e9e91dcd4..5a3ad5d6b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3430,31 +3430,6 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name } return sel; - } else if (type->kind == Type_Array) { - if (type->Array.count <= 4) { - // HACK(bill): Memory leak - switch (type->Array.count) { - #define _ARRAY_FIELD_CASE_IF(_length, _name) \ - if (field_name == (_name)) { \ - selection_add_index(&sel, (_length)-1); \ - sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), type->Array.elem, (_length)-1); \ - return sel; \ - } - #define _ARRAY_FIELD_CASE(_length, _name0, _name1) \ - case (_length): \ - _ARRAY_FIELD_CASE_IF(_length, _name0); \ - _ARRAY_FIELD_CASE_IF(_length, _name1); \ - /*fallthrough*/ - - _ARRAY_FIELD_CASE(4, "w", "a"); - _ARRAY_FIELD_CASE(3, "z", "b"); - _ARRAY_FIELD_CASE(2, "y", "g"); - _ARRAY_FIELD_CASE(1, "x", "r"); - default: break; - - #undef _ARRAY_FIELD_CASE - } - } } else if (type->kind == Type_DynamicArray) { GB_ASSERT(t_allocator != nullptr); String allocator_str = str_lit("allocator"); @@ -3475,7 +3450,53 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name sel.entity = entity__allocator; return sel; } + + +#define _ARRAY_FIELD_CASE_IF(_length, _name) \ + if (field_name == (_name)) { \ + selection_add_index(&sel, (_length)-1); \ + sel.entity = alloc_entity_array_elem(nullptr, make_token_ident(str_lit(_name)), elem, (_length)-1); \ + return sel; \ } +#define _ARRAY_FIELD_CASE(_length, _name0, _name1) \ +case (_length): \ + _ARRAY_FIELD_CASE_IF(_length, _name0); \ + _ARRAY_FIELD_CASE_IF(_length, _name1); \ + /*fallthrough*/ + + + } else if (type->kind == Type_Array) { + + Type *elem = type->Array.elem; + + if (type->Array.count <= 4) { + // HACK(bill): Memory leak + switch (type->Array.count) { + + _ARRAY_FIELD_CASE(4, "w", "a"); + _ARRAY_FIELD_CASE(3, "z", "b"); + _ARRAY_FIELD_CASE(2, "y", "g"); + _ARRAY_FIELD_CASE(1, "x", "r"); + default: break; + } + } + } else if (type->kind == Type_SimdVector) { + + Type *elem = type->SimdVector.elem; + if (type->SimdVector.count <= 4) { + // HACK(bill): Memory leak + switch (type->SimdVector.count) { + _ARRAY_FIELD_CASE(4, "w", "a"); + _ARRAY_FIELD_CASE(3, "z", "b"); + _ARRAY_FIELD_CASE(2, "y", "g"); + _ARRAY_FIELD_CASE(1, "x", "r"); + default: break; + } + } + } + +#undef _ARRAY_FIELD_CASE +#undef _ARRAY_FIELD_CASE return sel; } -- cgit v1.2.3 From a750fc0ba63c9f1461bba4cc0446b1b4c2d2b3a9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 19 Mar 2024 21:05:23 +0000 Subject: Add `#row_major matrix[R, C]T` As well as `#column_major matrix[R, C]T` as an alias for just `matrix[R, C]T`. This is because some libraries require a row_major internal layout but still want to be used with row or major oriented vectors. --- base/runtime/core.odin | 4 ++++ core/fmt/fmt.odin | 12 ++++++++++-- core/reflect/types.odin | 4 ++++ src/check_expr.cpp | 12 +++++++++--- src/check_type.cpp | 2 +- src/llvm_backend_const.cpp | 4 ++-- src/llvm_backend_expr.cpp | 39 +++++++++++++++++++++++++++++---------- src/llvm_backend_type.cpp | 3 ++- src/llvm_backend_utility.cpp | 22 +++++++++++++++------- src/parser.cpp | 13 +++++++++++++ src/parser.hpp | 1 + src/types.cpp | 19 +++++++++++++++---- 12 files changed, 105 insertions(+), 30 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/base/runtime/core.odin b/base/runtime/core.odin index 8f27ca674..7ad3ef1d6 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -177,6 +177,10 @@ Type_Info_Matrix :: struct { row_count: int, column_count: int, // Total element count = column_count * elem_stride + layout: enum u8 { + Column_Major, // array of column vectors + Row_Major, // array of row vectors + }, } Type_Info_Soa_Pointer :: struct { elem: ^Type_Info, diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 02803f882..6f9801bc8 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -2396,7 +2396,11 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix for col in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - offset := (row + col*info.elem_stride)*info.elem_size + offset: int + switch info.layout { + case .Column_Major: offset = (row + col*info.elem_stride)*info.elem_size + case .Row_Major: offset = (col + row*info.elem_stride)*info.elem_size + } data := uintptr(v.data) + uintptr(offset) fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) @@ -2410,7 +2414,11 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix for col in 0.. 0 { io.write_string(fi.writer, ", ", &fi.n) } - offset := (row + col*info.elem_stride)*info.elem_size + offset: int + switch info.layout { + case .Column_Major: offset = (row + col*info.elem_stride)*info.elem_size + case .Row_Major: offset = (col + row*info.elem_stride)*info.elem_size + } data := uintptr(v.data) + uintptr(offset) fmt_arg(fi, any{rawptr(data), info.elem.id}, verb) diff --git a/core/reflect/types.odin b/core/reflect/types.odin index 2b96dd4fb..9cff46a00 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -173,6 +173,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool { y := b.variant.(Type_Info_Matrix) or_return if x.row_count != y.row_count { return false } if x.column_count != y.column_count { return false } + if x.layout != y.layout { return false } return are_types_identical(x.elem, y.elem) case Type_Info_Bit_Field: @@ -689,6 +690,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) - write_type(w, info.pointer, &n) or_return case Type_Info_Matrix: + if info.layout == .Row_Major { + io.write_string(w, "#row_major ", &n) or_return + } io.write_string(w, "matrix[", &n) or_return io.write_i64(w, i64(info.row_count), 10, &n) or_return io.write_string(w, ", ", &n) or_return diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f359d5a54..67c7f1a04 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3431,6 +3431,11 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand if (xt->Matrix.column_count != yt->Matrix.row_count) { goto matrix_error; } + + if (xt->Matrix.is_row_major != yt->Matrix.is_row_major) { + goto matrix_error; + } + x->mode = Addressing_Value; if (are_types_identical(xt, yt)) { if (!is_type_named(x->type) && is_type_named(y->type)) { @@ -3438,7 +3443,8 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand x->type = y->type; } } else { - x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count); + bool is_row_major = xt->Matrix.is_row_major && yt->Matrix.is_row_major; + x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count, nullptr, nullptr, is_row_major); } goto matrix_success; } else if (yt->kind == Type_Array) { @@ -3452,7 +3458,7 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand // Treat arrays as column vectors x->mode = Addressing_Value; - if (type_hint == nullptr && xt->Matrix.row_count == yt->Array.count) { + if (xt->Matrix.row_count == yt->Array.count) { x->type = y->type; } else { x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, 1); @@ -3483,7 +3489,7 @@ gb_internal void check_binary_matrix(CheckerContext *c, Token const &op, Operand // Treat arrays as row vectors x->mode = Addressing_Value; - if (type_hint == nullptr && yt->Matrix.column_count == xt->Array.count) { + if (yt->Matrix.column_count == xt->Array.count) { x->type = x->type; } else { x->type = alloc_type_matrix(yt->Matrix.elem, 1, yt->Matrix.column_count); diff --git a/src/check_type.cpp b/src/check_type.cpp index d5cf187a4..3fe633892 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2658,7 +2658,7 @@ gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) } type_assign:; - *type = alloc_type_matrix(elem, row_count, column_count, generic_row, generic_column); + *type = alloc_type_matrix(elem, row_count, column_count, generic_row, generic_column, mt->is_row_major); return; } diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 2291f24ac..bbb0b8387 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -1302,11 +1302,11 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo GB_ASSERT_MSG(elem_count == max_count, "%td != %td", elem_count, max_count); LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)total_count); - for_array(i, cl->elems) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - i64 offset = matrix_row_major_index_to_offset(type, i); + i64 offset = 0; + offset = matrix_row_major_index_to_offset(type, i); values[offset] = lb_const_value(m, elem_type, tav.value, allow_local).value; } for (isize i = 0; i < total_count; i++) { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 98618798b..6eb8fdcc6 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -684,12 +684,6 @@ gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type Type *mt = base_type(m.type); GB_ASSERT(mt->kind == Type_Matrix); - // TODO(bill): Determine why this fails on Windows sometimes - if (false && 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; @@ -763,6 +757,7 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, 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)); + GB_ASSERT(xt->Matrix.is_row_major == yt->Matrix.is_row_major); Type *elem = xt->Matrix.elem; @@ -770,7 +765,7 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, unsigned inner = cast(unsigned)xt->Matrix.column_count; unsigned outer_columns = cast(unsigned)yt->Matrix.column_count; - if (lb_is_matrix_simdable(xt)) { + if (!xt->Matrix.is_row_major && 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); @@ -812,7 +807,7 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, return lb_addr_load(p, res); } - { + if (!xt->Matrix.is_row_major) { lbAddr res = lb_add_local_generated(p, type, true); auto inners = slice_make(permanent_allocator(), inner); @@ -835,6 +830,30 @@ gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, } } + return lb_addr_load(p, res); + } else { + lbAddr res = lb_add_local_generated(p, type, true); + + auto inners = slice_make(permanent_allocator(), inner); + + for (unsigned i = 0; i < outer_rows; i++) { + for (unsigned j = 0; j < outer_columns; j++) { + lbValue dst = lb_emit_matrix_epi(p, res.addr, i, j); + for (unsigned k = 0; k < inner; k++) { + 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]; + lbValue b = inners[k][1]; + sum = lb_emit_mul_add(p, a, b, sum, elem); + } + lb_emit_store(p, dst, sum); + } + } + return lb_addr_load(p, res); } } @@ -855,7 +874,7 @@ gb_internal lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbVal Type *elem = mt->Matrix.elem; - if (lb_is_matrix_simdable(mt)) { + if (!mt->Matrix.is_row_major && lb_is_matrix_simdable(mt)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; @@ -924,7 +943,7 @@ gb_internal lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbVal Type *elem = mt->Matrix.elem; - if (lb_is_matrix_simdable(mt)) { + if (!mt->Matrix.is_row_major && lb_is_matrix_simdable(mt)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index aec1fb201..de83f5058 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -979,12 +979,13 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ tag_type = t_type_info_matrix; i64 ez = type_size_of(t->Matrix.elem); - LLVMValueRef vals[5] = { + LLVMValueRef vals[6] = { get_type_info_ptr(m, t->Matrix.elem), 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, lb_const_int(m, t_int, t->Matrix.column_count).value, + lb_const_int(m, t_u8, cast(u8)t->Matrix.is_row_major).value, }; variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index f18aa5521..fb61c41c3 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1464,14 +1464,16 @@ gb_internal lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isi Type *t = s.type; GB_ASSERT(is_type_pointer(t)); 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_epi(p, s, row); - } else if (row == 0 && is_type_array_like(mt)) { - return lb_emit_epi(p, s, column); + + if (!mt->Matrix.is_row_major) { + if (column == 0) { + GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt)); + return lb_emit_epi(p, s, row); + } else if (row == 0 && is_type_array_like(mt)) { + 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); @@ -1491,7 +1493,13 @@ gb_internal lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lb row = lb_emit_conv(p, row, t_int); column = lb_emit_conv(p, column, t_int); - LLVMValueRef index = LLVMBuildAdd(p->builder, row.value, LLVMBuildMul(p->builder, column.value, stride_elems, ""), ""); + LLVMValueRef index = nullptr; + + if (mt->Matrix.is_row_major) { + index = LLVMBuildAdd(p->builder, column.value, LLVMBuildMul(p->builder, row.value, stride_elems, ""), ""); + } else { + index = LLVMBuildAdd(p->builder, row.value, LLVMBuildMul(p->builder, column.value, stride_elems, ""), ""); + } LLVMValueRef indices[2] = { LLVMConstInt(lb_type(p->module, t_int), 0, false), diff --git a/src/parser.cpp b/src/parser.cpp index 1aa40ccbf..eb9e73342 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2329,6 +2329,19 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { break; } return original_type; + } else if (name.string == "row_major" || + name.string == "column_major") { + Ast *original_type = parse_type(f); + Ast *type = unparen_expr(original_type); + switch (type->kind) { + case Ast_MatrixType: + type->MatrixType.is_row_major = (name.string == "row_major"); + break; + default: + syntax_error(type, "Expected a matrix type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind])); + break; + } + return original_type; } else if (name.string == "partial") { Ast *tag = ast_basic_directive(f, token, name); Ast *original_expr = parse_expr(f, lhs); diff --git a/src/parser.hpp b/src/parser.hpp index f5997c4bd..ff3c5eb34 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -772,6 +772,7 @@ AST_KIND(_TypeBegin, "", bool) \ Ast *row_count; \ Ast *column_count; \ Ast *elem; \ + bool is_row_major; \ }) \ AST_KIND(_TypeEnd, "", bool) diff --git a/src/types.cpp b/src/types.cpp index 5a3ad5d6b..ab5e4de03 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -281,6 +281,7 @@ struct TypeProc { Type *generic_row_count; \ Type *generic_column_count; \ i64 stride_in_bytes; \ + bool is_row_major; \ }) \ TYPE_KIND(BitField, struct { \ Scope * scope; \ @@ -1002,7 +1003,7 @@ gb_internal Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = return t; } -gb_internal Type *alloc_type_matrix(Type *elem, i64 row_count, i64 column_count, Type *generic_row_count = nullptr, Type *generic_column_count = nullptr) { +gb_internal Type *alloc_type_matrix(Type *elem, i64 row_count, i64 column_count, Type *generic_row_count = nullptr, Type *generic_column_count = nullptr, bool is_row_major = false) { if (generic_row_count != nullptr || generic_column_count != nullptr) { Type *t = alloc_type(Type_Matrix); t->Matrix.elem = elem; @@ -1010,12 +1011,14 @@ gb_internal Type *alloc_type_matrix(Type *elem, i64 row_count, i64 column_count, t->Matrix.column_count = column_count; t->Matrix.generic_row_count = generic_row_count; t->Matrix.generic_column_count = generic_column_count; + t->Matrix.is_row_major = is_row_major; return t; } Type *t = alloc_type(Type_Matrix); t->Matrix.elem = elem; t->Matrix.row_count = row_count; t->Matrix.column_count = column_count; + t->Matrix.is_row_major = is_row_major; return t; } @@ -1512,14 +1515,18 @@ gb_internal i64 matrix_indices_to_offset(Type *t, i64 row_index, i64 column_inde GB_ASSERT(0 <= row_index && row_index < t->Matrix.row_count); GB_ASSERT(0 <= column_index && column_index < t->Matrix.column_count); i64 stride_elems = matrix_type_stride_in_elems(t); - // NOTE(bill): Column-major layout internally - return row_index + stride_elems*column_index; + if (t->Matrix.is_row_major) { + return column_index + stride_elems*row_index; + } else { + // NOTE(bill): Column-major layout internally + return row_index + stride_elems*column_index; + } } gb_internal i64 matrix_row_major_index_to_offset(Type *t, i64 index) { t = base_type(t); GB_ASSERT(t->kind == Type_Matrix); - + i64 row_index = index/t->Matrix.column_count; i64 column_index = index%t->Matrix.column_count; return matrix_indices_to_offset(t, row_index, column_index); @@ -2690,6 +2697,7 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_Matrix: return x->Matrix.row_count == y->Matrix.row_count && x->Matrix.column_count == y->Matrix.column_count && + x->Matrix.is_row_major == y->Matrix.is_row_major && are_types_identical(x->Matrix.elem, y->Matrix.elem); case Type_DynamicArray: @@ -4735,6 +4743,9 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha break; case Type_Matrix: + if (type->Matrix.is_row_major) { + str = gb_string_appendc(str, "#row_major "); + } str = gb_string_appendc(str, gb_bprintf("matrix[%d, %d]", cast(int)type->Matrix.row_count, cast(int)type->Matrix.column_count)); str = write_type_to_string(str, type->Matrix.elem); break; -- cgit v1.2.3 From 3bff922b6f066966c550cf6298ab3f2a564f6c5e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 20 Mar 2024 10:23:57 +0000 Subject: `m[i]` on `#row_major` matrices will reduce the i-th row-vector --- src/llvm_backend_expr.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 6eb8fdcc6..06bf9fe1e 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3990,7 +3990,13 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { } 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); + + lbValue elem = {}; + if (t->Matrix.is_row_major) { + elem = lb_emit_matrix_ep(p, matrix, index, lb_const_int(p->module, t_int, 0)); + } else { + 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); -- cgit v1.2.3 From 553a244fec29f4bf2b32f9813ceb578fa46909fd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 20 Mar 2024 10:24:39 +0000 Subject: Fix bounds checking --- src/llvm_backend_expr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 06bf9fe1e..12949f0ab 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3991,17 +3991,20 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { lbValue index = lb_build_expr(p, ie->index); index = lb_emit_conv(p, index, t_int); + isize bounds_len = 0; lbValue elem = {}; if (t->Matrix.is_row_major) { + bounds_len = t->Matrix.row_count; elem = lb_emit_matrix_ep(p, matrix, index, lb_const_int(p->module, t_int, 0)); } else { + bounds_len = t->Matrix.column_count; 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); + lbValue len = lb_const_int(p->module, t_int, bounds_len); lb_emit_bounds_check(p, ast_token(ie->index), index, len); } return lb_addr(elem); -- cgit v1.2.3 From b862691d7524d5dc05d6c43872daa7a488c2411a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 1 Apr 2024 13:08:07 +0100 Subject: Support `for in` with `bit_set` --- src/check_stmt.cpp | 13 ++++++ src/llvm_backend_expr.cpp | 102 +++++++++++++++++++++++----------------------- src/llvm_backend_stmt.cpp | 94 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 152 insertions(+), 57 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 1d7e7d4e9..b25df01a6 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1554,6 +1554,19 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } break; + case Type_BitSet: + array_add(&vals, t->BitSet.elem); + if (rs->vals.count > 1) { + error(rs->vals[1], "Expected 1 name when iterating over a bit_set, got %td", rs->vals.count); + } + if (rs->vals.count == 1 && + rs->vals[0]->kind == Ast_UnaryExpr && + rs->vals[0]->UnaryExpr.op.kind == Token_And) { + error(rs->vals[0], "When iteraing across a bit_set, you cannot modify the value with '&' as that does not make much sense"); + } + add_type_info_type(ctx, operand.type); + break; + case Type_EnumeratedArray: if (is_ptr) use_by_reference_for_value = true; array_add(&vals, t->EnumeratedArray.elem); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 12949f0ab..f6f36e861 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1373,6 +1373,57 @@ gb_internal bool lb_is_empty_string_constant(Ast *expr) { return false; } +gb_internal lbValue lb_build_binary_in(lbProcedure *p, lbValue left, lbValue right, TokenKind op) { + Type *rt = base_type(right.type); + if (is_type_pointer(rt)) { + right = lb_emit_load(p, right); + rt = base_type(type_deref(rt)); + } + + switch (rt->kind) { + case Type_Map: + { + lbValue map_ptr = lb_address_from_load_or_generate_local(p, right); + lbValue key = left; + lbValue ptr = lb_internal_dynamic_map_get_ptr(p, map_ptr, key); + if (op == Token_in) { + return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool); + } else { + return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_CmpEq, ptr), t_bool); + } + } + break; + case Type_BitSet: + { + Type *key_type = rt->BitSet.elem; + GB_ASSERT(are_types_identical(left.type, key_type)); + + Type *it = bit_set_to_int(rt); + left = lb_emit_conv(p, left, it); + if (is_type_different_to_arch_endianness(it)) { + left = lb_emit_byte_swap(p, left, integer_endian_type_to_platform_type(it)); + } + + lbValue lower = lb_const_value(p->module, left.type, exact_value_i64(rt->BitSet.lower)); + lbValue key = lb_emit_arith(p, Token_Sub, left, lower, left.type); + lbValue bit = lb_emit_arith(p, Token_Shl, lb_const_int(p->module, left.type, 1), key, left.type); + bit = lb_emit_conv(p, bit, it); + + lbValue old_value = lb_emit_transmute(p, right, it); + lbValue new_value = lb_emit_arith(p, Token_And, old_value, bit, it); + + if (op == Token_in) { + return lb_emit_conv(p, lb_emit_comp(p, Token_NotEq, new_value, lb_const_int(p->module, new_value.type, 0)), t_bool); + } else { + return lb_emit_conv(p, lb_emit_comp(p, Token_CmpEq, new_value, lb_const_int(p->module, new_value.type, 0)), t_bool); + } + } + break; + } + GB_PANIC("Invalid 'in' type"); + return {}; +} + gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { ast_node(be, BinaryExpr, expr); @@ -1480,57 +1531,8 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { { lbValue left = lb_build_expr(p, be->left); lbValue right = lb_build_expr(p, be->right); - Type *rt = base_type(right.type); - if (is_type_pointer(rt)) { - right = lb_emit_load(p, right); - rt = base_type(type_deref(rt)); - } - - switch (rt->kind) { - case Type_Map: - { - lbValue map_ptr = lb_address_from_load_or_generate_local(p, right); - lbValue key = left; - lbValue ptr = lb_internal_dynamic_map_get_ptr(p, map_ptr, key); - if (be->op.kind == Token_in) { - return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool); - } else { - return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_CmpEq, ptr), t_bool); - } - } - break; - case Type_BitSet: - { - Type *key_type = rt->BitSet.elem; - GB_ASSERT(are_types_identical(left.type, key_type)); - - Type *it = bit_set_to_int(rt); - left = lb_emit_conv(p, left, it); - if (is_type_different_to_arch_endianness(it)) { - left = lb_emit_byte_swap(p, left, integer_endian_type_to_platform_type(it)); - } - - lbValue lower = lb_const_value(p->module, left.type, exact_value_i64(rt->BitSet.lower)); - lbValue key = lb_emit_arith(p, Token_Sub, left, lower, left.type); - lbValue bit = lb_emit_arith(p, Token_Shl, lb_const_int(p->module, left.type, 1), key, left.type); - bit = lb_emit_conv(p, bit, it); - - lbValue old_value = lb_emit_transmute(p, right, it); - lbValue new_value = lb_emit_arith(p, Token_And, old_value, bit, it); - - if (be->op.kind == Token_in) { - return lb_emit_conv(p, lb_emit_comp(p, Token_NotEq, new_value, lb_const_int(p->module, new_value.type, 0)), t_bool); - } else { - return lb_emit_conv(p, lb_emit_comp(p, Token_CmpEq, new_value, lb_const_int(p->module, new_value.type, 0)), t_bool); - } - } - break; - default: - GB_PANIC("Invalid 'in' type"); - } - break; + return lb_build_binary_in(p, left, right, be->op.kind); } - break; default: GB_PANIC("Invalid binary expression"); break; diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 4ecf70ec4..24dd321f6 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -737,6 +737,22 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lb_start_block(p, done); } +gb_internal lbValue lb_enum_values_slice(lbProcedure *p, Type *enum_type, i64 *enum_count_) { + Type *t = enum_type; + GB_ASSERT(is_type_enum(t)); + t = base_type(t); + GB_ASSERT(t->kind == Type_Enum); + i64 enum_count = t->Enum.fields.count; + + if (enum_count_) *enum_count_ = enum_count; + + lbValue ti = lb_type_info(p, t); + lbValue variant = lb_emit_struct_ep(p, ti, 4); + lbValue eti_ptr = lb_emit_conv(p, variant, t_type_info_enum_ptr); + lbValue values = lb_emit_load(p, lb_emit_struct_ep(p, eti_ptr, 2)); + return values; +} + gb_internal void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) { lbModule *m = p->module; @@ -744,15 +760,11 @@ gb_internal void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_ GB_ASSERT(is_type_enum(t)); t = base_type(t); Type *core_elem = core_type(t); - GB_ASSERT(t->kind == Type_Enum); - i64 enum_count = t->Enum.fields.count; - lbValue max_count = lb_const_int(m, t_int, enum_count); + i64 enum_count = 0; - lbValue ti = lb_type_info(p, t); - lbValue variant = lb_emit_struct_ep(p, ti, 4); - lbValue eti_ptr = lb_emit_conv(p, variant, t_type_info_enum_ptr); - lbValue values = lb_emit_load(p, lb_emit_struct_ep(p, eti_ptr, 2)); + lbValue values = lb_enum_values_slice(p, enum_type, &enum_count); lbValue values_data = lb_slice_elem(p, values); + lbValue max_count = lb_const_int(m, t_int, enum_count); lbAddr offset_ = lb_add_local_generated(p, t_int, false); lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); @@ -1052,6 +1064,74 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc case Type_Tuple: lb_build_range_tuple(p, expr, val0_type, val1_type, &val, &key, &loop, &done); break; + + case Type_BitSet: { + lbModule *m = p->module; + + lbValue the_set = lb_build_expr(p, expr); + if (is_type_pointer(type_deref(the_set.type))) { + the_set = lb_emit_load(p, the_set); + } + + Type *elem = et->BitSet.elem; + if (is_type_enum(elem)) { + i64 enum_count = 0; + lbValue values = lb_enum_values_slice(p, elem, &enum_count); + lbValue values_data = lb_slice_elem(p, values); + lbValue max_count = lb_const_int(m, t_int, enum_count); + + lbAddr offset_ = lb_add_local_generated(p, t_int, false); + lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); + + loop = lb_create_block(p, "for.bit_set.enum.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + lbBlock *body_check = lb_create_block(p, "for.bit_set.enum.body-check"); + lbBlock *body = lb_create_block(p, "for.bit_set.enum.body"); + done = lb_create_block(p, "for.bit_set.enum.done"); + + lbValue offset = lb_addr_load(p, offset_); + lbValue cond = lb_emit_comp(p, Token_Lt, offset, max_count); + lb_emit_if(p, cond, body_check, done); + lb_start_block(p, body_check); + + lbValue val_ptr = lb_emit_ptr_offset(p, values_data, offset); + lb_emit_increment(p, offset_.addr); + val = lb_emit_load(p, val_ptr); + val = lb_emit_conv(p, val, elem); + + lbValue check = lb_build_binary_in(p, val, the_set, Token_in); + lb_emit_if(p, check, body, loop); + lb_start_block(p, body); + } else { + lbAddr offset_ = lb_add_local_generated(p, t_int, false); + lb_addr_store(p, offset_, lb_const_int(m, t_int, et->BitSet.lower)); + + lbValue max_count = lb_const_int(m, t_int, et->BitSet.upper); + + loop = lb_create_block(p, "for.bit_set.range.loop"); + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + lbBlock *body_check = lb_create_block(p, "for.bit_set.range.body-check"); + lbBlock *body = lb_create_block(p, "for.bit_set.range.body"); + done = lb_create_block(p, "for.bit_set.range.done"); + + lbValue offset = lb_addr_load(p, offset_); + lbValue cond = lb_emit_comp(p, Token_LtEq, offset, max_count); + lb_emit_if(p, cond, body_check, done); + lb_start_block(p, body_check); + + val = lb_emit_conv(p, offset, elem); + lb_emit_increment(p, offset_.addr); + + lbValue check = lb_build_binary_in(p, val, the_set, Token_in); + lb_emit_if(p, check, body, loop); + lb_start_block(p, body); + } + break; + } default: GB_PANIC("Cannot range over %s", type_to_string(expr_type)); break; -- cgit v1.2.3 From 5339e1e1b6824b67fbbe195e18d1122bda3dd6f7 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 3 Apr 2024 21:21:46 +0200 Subject: fix objc proc group edge case Fixes #2648 --- src/llvm_backend_expr.cpp | 6 ++++-- src/types.cpp | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index f6f36e861..0649150ca 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4677,8 +4677,10 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { 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_ASSERT(sel.entity->kind == Entity_Procedure || sel.entity->kind == Entity_ProcGroup); + Entity *e = entity_of_node(sel_node); + GB_ASSERT(e->kind == Entity_Procedure); + return lb_addr(lb_find_value_from_entity(p->module, e)); } GB_PANIC("Unreachable %.*s", LIT(selector)); } diff --git a/src/types.cpp b/src/types.cpp index 0bf28a28c..97512d29b 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3158,7 +3158,7 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name mutex_lock(md->mutex); defer (mutex_unlock(md->mutex)); for (TypeNameObjCMetadataEntry const &entry : md->type_entries) { - GB_ASSERT(entry.entity->kind == Entity_Procedure); + GB_ASSERT(entry.entity->kind == Entity_Procedure || entry.entity->kind == Entity_ProcGroup); if (entry.name == field_name) { sel.entity = entry.entity; sel.pseudo_field = true; -- cgit v1.2.3 From 13e459980b0143b49762cdfd04dd5cf1bbf83daa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 10 Apr 2024 16:18:44 +0100 Subject: Fix `ptr_to_bit_field.field` --- src/llvm_backend_expr.cpp | 5 ++++- src/llvm_backend_general.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'src/llvm_backend_expr.cpp') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 0649150ca..fcec59968 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -4726,9 +4726,12 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { if (sub_sel.index.count > 0) { ptr = lb_emit_deep_field_gep(p, ptr, sub_sel); } + if (is_type_pointer(type_deref(ptr.type))) { + ptr = lb_emit_load(p, ptr); + } Type *bf_type = type_deref(ptr.type); - bf_type = base_type(type_deref(bf_type)); + bf_type = base_type(bf_type); GB_ASSERT(bf_type->kind == Type_BitField); i32 index = sel.index[sel.index.count-1]; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 889cb8822..0d8d9258a 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -453,7 +453,7 @@ gb_internal lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slice