mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-05 02:04:06 +00:00
Add general support for bit_fields
This commit is contained in:
@@ -1034,3 +1034,25 @@ fixdfti :: proc(a: u64) -> i128 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
__write_bits :: proc "contextless" (dst, src: [^]byte, offset: uintptr, size: uintptr) {
|
||||
for i in 0..<size {
|
||||
j := offset+i
|
||||
the_bit := byte((src[i/8]) & (1<<(i&7)) != 0)
|
||||
b := the_bit<<(j&7)
|
||||
dst[j/8] &~= b
|
||||
dst[j/8] |= b
|
||||
}
|
||||
}
|
||||
|
||||
__read_bits :: proc "contextless" (dst, src: [^]byte, offset: uintptr, size: uintptr) {
|
||||
for j in 0..<size {
|
||||
i := offset+j
|
||||
the_bit := byte((src[i/8]) & (1<<(i&7)) != 0)
|
||||
b := the_bit<<(j&7)
|
||||
dst[j/8] &~= b
|
||||
dst[j/8] |= b
|
||||
}
|
||||
}
|
||||
@@ -2331,13 +2331,19 @@ fmt_bit_field :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Bit
|
||||
io.write_string(fi.writer, name, &fi.n)
|
||||
io.write_string(fi.writer, " = ", &fi.n)
|
||||
|
||||
|
||||
bit_offset := info.bit_offsets[i]
|
||||
bit_size := info.bit_sizes[i]
|
||||
|
||||
value := read_bits(([^]byte)(v.data), bit_offset, bit_size)
|
||||
type := info.types[i]
|
||||
|
||||
fmt_value(fi, any{&value, info.types[i].id}, verb)
|
||||
if !reflect.is_unsigned(runtime.type_info_core(type)) {
|
||||
// Sign Extension
|
||||
m := u64(1<<(bit_size-1))
|
||||
value = (value ~ m) - m
|
||||
}
|
||||
|
||||
fmt_value(fi, any{&value, type.id}, verb)
|
||||
if do_trailing_comma { io.write_string(fi.writer, ",\n", &fi.n) }
|
||||
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ gb_internal void check_union_type (CheckerContext *c, Type *un
|
||||
gb_internal Type * check_init_variable (CheckerContext *c, Entity *e, Operand *operand, String context_name);
|
||||
|
||||
|
||||
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=0);
|
||||
gb_internal void add_map_key_type_dependencies(CheckerContext *ctx, Type *key);
|
||||
|
||||
gb_internal Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem);
|
||||
@@ -2071,11 +2071,17 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, Type *type) {
|
||||
gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, Type *type, i64 max_bit_size=0) {
|
||||
if (is_type_integer(type) && o->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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<i64>(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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -84,6 +84,8 @@ enum lbAddrKind {
|
||||
|
||||
lbAddr_Swizzle,
|
||||
lbAddr_SwizzleLarge,
|
||||
|
||||
lbAddr_BitField,
|
||||
};
|
||||
|
||||
struct lbAddr {
|
||||
@@ -118,6 +120,12 @@ struct lbAddr {
|
||||
Type *type;
|
||||
Slice<i32> indices;
|
||||
} swizzle_large;
|
||||
struct {
|
||||
Type *type;
|
||||
i64 index;
|
||||
i64 bit_offset;
|
||||
i64 bit_size;
|
||||
} bitfield;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -451,6 +451,20 @@ gb_internal lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slice<i
|
||||
return v;
|
||||
}
|
||||
|
||||
gb_internal lbAddr lb_addr_bit_field(lbValue addr, Type *type, i64 index, i64 bit_offset, i64 bit_size) {
|
||||
GB_ASSERT(is_type_pointer(addr.type));
|
||||
Type *mt = type_deref(addr.type);
|
||||
GB_ASSERT(is_type_bit_field(mt));
|
||||
|
||||
lbAddr v = {lbAddr_BitField, addr};
|
||||
v.bitfield.type = type;
|
||||
v.bitfield.index = index;
|
||||
v.bitfield.bit_offset = bit_offset;
|
||||
v.bitfield.bit_size = bit_size;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
gb_internal Type *lb_addr_type(lbAddr const &addr) {
|
||||
if (addr.addr.value == nullptr) {
|
||||
return nullptr;
|
||||
@@ -759,7 +773,17 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
|
||||
addr = lb_addr(lb_address_from_load(p, lb_addr_load(p, addr)));
|
||||
}
|
||||
|
||||
if (addr.kind == lbAddr_RelativePointer) {
|
||||
if (addr.kind == lbAddr_BitField) {
|
||||
lbValue dst = addr.addr;
|
||||
|
||||
auto args = array_make<lbValue>(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<lbValue>(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;
|
||||
|
||||
@@ -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 { \
|
||||
|
||||
@@ -287,6 +287,7 @@ struct TypeProc {
|
||||
Type * backing_type; \
|
||||
Slice<Entity *> fields; \
|
||||
Slice<u8> bit_sizes; \
|
||||
Slice<i64> 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;
|
||||
|
||||
Reference in New Issue
Block a user