Browse Source

Begin work adding `bit_field`

gingerBill 1 year ago
parent
commit
a4b8c1ea17

+ 9 - 0
base/runtime/core.odin

@@ -181,6 +181,13 @@ Type_Info_Matrix :: struct {
 Type_Info_Soa_Pointer :: struct {
 Type_Info_Soa_Pointer :: struct {
 	elem: ^Type_Info,
 	elem: ^Type_Info,
 }
 }
+Type_Info_Bit_Field :: struct {
+	backing_type: ^Type_Info,
+	names:        []string,
+	types:        []^Type_Info,
+	bit_sizes:    []uintptr,
+	bit_offsets:  []uintptr,
+}
 
 
 Type_Info_Flag :: enum u8 {
 Type_Info_Flag :: enum u8 {
 	Comparable     = 0,
 	Comparable     = 0,
@@ -223,6 +230,7 @@ Type_Info :: struct {
 		Type_Info_Relative_Multi_Pointer,
 		Type_Info_Relative_Multi_Pointer,
 		Type_Info_Matrix,
 		Type_Info_Matrix,
 		Type_Info_Soa_Pointer,
 		Type_Info_Soa_Pointer,
+		Type_Info_Bit_Field,
 	},
 	},
 }
 }
 
 
@@ -256,6 +264,7 @@ Typeid_Kind :: enum u8 {
 	Relative_Multi_Pointer,
 	Relative_Multi_Pointer,
 	Matrix,
 	Matrix,
 	Soa_Pointer,
 	Soa_Pointer,
+	Bit_Field,
 }
 }
 #assert(len(Typeid_Kind) < 32)
 #assert(len(Typeid_Kind) < 32)
 
 

+ 14 - 0
base/runtime/print.odin

@@ -459,6 +459,20 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
 		}
 		}
 		print_byte(']')
 		print_byte(']')
 
 
+	case Type_Info_Bit_Field:
+		print_string("bit_field ")
+		print_type(info.backing_type)
+		print_string(" {")
+		for name, i in info.names {
+			if i > 0 { print_string(", ") }
+			print_string(name)
+			print_string(": ")
+			print_type(info.types[i])
+			print_string(" | ")
+			print_u64(u64(info.bit_sizes[i]))
+		}
+		print_byte('}')
+
 
 
 	case Type_Info_Simd_Vector:
 	case Type_Info_Simd_Vector:
 		print_string("#simd[")
 		print_string("#simd[")

+ 3 - 0
core/encoding/json/marshal.odin

@@ -228,6 +228,9 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
 	case runtime.Type_Info_Matrix:
 	case runtime.Type_Info_Matrix:
 		return .Unsupported_Type
 		return .Unsupported_Type
 
 
+	case runtime.Type_Info_Bit_Field:
+		return .Unsupported_Type
+
 	case runtime.Type_Info_Array:
 	case runtime.Type_Info_Array:
 		opt_write_start(w, opt, '[') or_return
 		opt_write_start(w, opt, '[') or_return
 		for i in 0..<info.count {
 		for i in 0..<info.count {

+ 65 - 0
core/fmt/fmt.odin

@@ -2283,6 +2283,68 @@ fmt_matrix :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Matrix
 		fmt_write_indent(fi)
 		fmt_write_indent(fi)
 	}
 	}
 }
 }
+
+fmt_bit_field :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Bit_Field) {
+	read_bits :: proc(ptr: [^]byte, offset, size: uintptr) -> (res: u64) {
+		for i in 0..<size {
+			j := i+offset
+			B := ptr[j/8]
+			k := j&7
+			if B & (u8(1)<<k) != 0 {
+				res |= u64(1)<<u64(i)
+			}
+		}
+		return
+	}
+
+	io.write_string(fi.writer, "bit_field{", &fi.n)
+
+	hash   := fi.hash;   defer fi.hash = hash
+	indent := fi.indent; defer fi.indent -= 1
+	do_trailing_comma := hash
+
+	fi.indent += 1
+
+	if hash	{
+		io.write_byte(fi.writer, '\n', &fi.n)
+	}
+	defer {
+		if hash {
+			for _ in 0..<indent { io.write_byte(fi.writer, '\t', &fi.n) }
+		}
+		io.write_byte(fi.writer, '}', &fi.n)
+	}
+
+
+	field_count := -1
+	for name, i in info.names {
+		_ = i
+		field_count += 1
+
+		if !do_trailing_comma && field_count > 0 {
+			io.write_string(fi.writer, ", ")
+		}
+		if hash {
+			fmt_write_indent(fi)
+		}
+
+		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)
+
+		fmt_value(fi, any{&value, info.types[i].id}, verb)
+		if do_trailing_comma { io.write_string(fi.writer, ",\n", &fi.n) }
+
+	}
+}
+
+
+
 // Formats a value based on its type and formatting verb
 // Formats a value based on its type and formatting verb
 //
 //
 // Inputs:
 // Inputs:
@@ -2611,6 +2673,9 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
 
 
 	case runtime.Type_Info_Matrix:
 	case runtime.Type_Info_Matrix:
 		fmt_matrix(fi, v, verb, info)
 		fmt_matrix(fi, v, verb, info)
+
+	case runtime.Type_Info_Bit_Field:
+		fmt_bit_field(fi, v, verb, info)
 	}
 	}
 }
 }
 // Formats a complex number based on the given formatting verb
 // Formats a complex number based on the given formatting verb

+ 10 - 0
core/reflect/reflect.odin

@@ -35,6 +35,7 @@ Type_Info_Relative_Pointer       :: runtime.Type_Info_Relative_Pointer
 Type_Info_Relative_Multi_Pointer :: runtime.Type_Info_Relative_Multi_Pointer
 Type_Info_Relative_Multi_Pointer :: runtime.Type_Info_Relative_Multi_Pointer
 Type_Info_Matrix                 :: runtime.Type_Info_Matrix
 Type_Info_Matrix                 :: runtime.Type_Info_Matrix
 Type_Info_Soa_Pointer            :: runtime.Type_Info_Soa_Pointer
 Type_Info_Soa_Pointer            :: runtime.Type_Info_Soa_Pointer
+Type_Info_Bit_Field              :: runtime.Type_Info_Bit_Field
 
 
 Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value
 Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value
 
 
@@ -70,6 +71,7 @@ Type_Kind :: enum {
 	Relative_Multi_Pointer,
 	Relative_Multi_Pointer,
 	Matrix,
 	Matrix,
 	Soa_Pointer,
 	Soa_Pointer,
+	Bit_Field,
 }
 }
 
 
 
 
@@ -106,6 +108,7 @@ type_kind :: proc(T: typeid) -> Type_Kind {
 		case Type_Info_Relative_Multi_Pointer: return .Relative_Multi_Pointer
 		case Type_Info_Relative_Multi_Pointer: return .Relative_Multi_Pointer
 		case Type_Info_Matrix:                 return .Matrix
 		case Type_Info_Matrix:                 return .Matrix
 		case Type_Info_Soa_Pointer:            return .Soa_Pointer
 		case Type_Info_Soa_Pointer:            return .Soa_Pointer
+		case Type_Info_Bit_Field:              return .Bit_Field
 		}
 		}
 
 
 	}
 	}
@@ -1604,6 +1607,13 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
 			}	
 			}	
 		}
 		}
 		return true
 		return true
+
+	case Type_Info_Bit_Field:
+		x, y := a, b
+		x.id = v.backing_type.id
+		y.id = v.backing_type.id
+		return equal(x, y, including_indirect_array_recursion, recursion_level+0)
+
 	}
 	}
 	
 	
 	runtime.print_typeid(a.id)
 	runtime.print_typeid(a.id)

+ 31 - 0
core/reflect/types.odin

@@ -174,6 +174,23 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
 		if x.row_count != y.row_count { return false }
 		if x.row_count != y.row_count { return false }
 		if x.column_count != y.column_count { return false }
 		if x.column_count != y.column_count { return false }
 		return are_types_identical(x.elem, y.elem)
 		return are_types_identical(x.elem, y.elem)
+
+	case Type_Info_Bit_Field:
+		y := b.variant.(Type_Info_Bit_Field) or_return
+		if !are_types_identical(x.backing_type, y.backing_type) { return false }
+		if len(x.names) != len(y.names) { return false }
+		for _, i in x.names {
+			if x.names[i] != y.names[i] {
+				return false
+			}
+			if !are_types_identical(x.types[i], y.types[i]) {
+				return false
+			}
+			if x.bit_sizes[i] != y.bit_sizes[i] {
+				return false
+			}
+		}
+		return true
 	}
 	}
 
 
 	return false
 	return false
@@ -639,6 +656,20 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
 		}
 		}
 		io.write_byte(w, ']', &n) or_return
 		io.write_byte(w, ']', &n) or_return
 
 
+	case Type_Info_Bit_Field:
+		io.write_string(w, "bit_field ", &n) or_return
+		write_type(w, info.backing_type, &n) or_return
+		io.write_string(w, " {",         &n) or_return
+		for name, i in info.names {
+			if i > 0 { io.write_string(w, ", ", &n) or_return }
+			io.write_string(w, name,     &n) or_return
+			io.write_string(w, ": ",     &n) or_return
+			write_type(w, info.types[i], &n) or_return
+			io.write_string(w, " | ",    &n) or_return
+			io.write_u64(w, u64(info.bit_sizes[i]), 10, &n) or_return
+		}
+		io.write_string(w, "}", &n) or_return
+
 	case Type_Info_Simd_Vector:
 	case Type_Info_Simd_Vector:
 		io.write_string(w, "#simd[",         &n) or_return
 		io.write_string(w, "#simd[",         &n) or_return
 		io.write_i64(w, i64(info.count), 10, &n) or_return
 		io.write_i64(w, i64(info.count), 10, &n) or_return

+ 152 - 0
src/check_type.cpp

@@ -925,6 +925,144 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam
 	enum_type->Enum.max_value_index = max_value_index;
 	enum_type->Enum.max_value_index = max_value_index;
 }
 }
 
 
+gb_internal bool is_valid_bit_field_backing_type(Type *type) {
+	if (type == nullptr) {
+		return nullptr;
+	}
+	type = base_type(type);
+	if (is_type_untyped(type)) {
+		return false;
+	}
+	if (is_type_integer(type)) {
+		return true;
+	}
+	if (type->kind == Type_Array) {
+		return is_type_integer(type->Array.elem);
+	}
+	return false;
+}
+
+gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, Type *named_type, Ast *node) {
+	ast_node(bf, BitFieldType, node);
+	GB_ASSERT(is_type_bit_field(bit_field_type));
+
+	Type *backing_type = check_type(ctx, bf->backing_type);
+	if (backing_type == nullptr || !is_valid_bit_field_backing_type(backing_type)) {
+		error(node, "Backing type for a bit_field must be an integer or an array of an integer");
+		return;
+	}
+
+	bit_field_type->BitField.backing_type = backing_type;
+	bit_field_type->BitField.scope = ctx->scope;
+
+	auto fields    = array_make<Entity *>(permanent_allocator(), 0, bf->fields.count);
+	auto bit_sizes = array_make<u8>      (permanent_allocator(), 0, bf->fields.count);
+
+	u64 maximum_bit_size = 8 * type_size_of(backing_type);
+	u64 total_bit_size = 0;
+
+	for_array(i, bf->fields) {
+		i32 field_src_index = cast(i32)i;
+		Ast *field = bf->fields[i];
+		if (field->kind != Ast_BitFieldField) {
+			error(field, "Invalid AST for a bit_field");
+			continue;
+		}
+		ast_node(f, BitFieldField, field);
+		if (f->name == nullptr || f->name->kind != Ast_Ident) {
+			error(field, "A bit_field's field name must be an identifier");
+			continue;
+		}
+		CommentGroup *docs    = f->docs;
+		CommentGroup *comment = f->comment;
+
+		String name = f->name->Ident.token.string;
+
+		if (f->type == nullptr) {
+			error(field, "A bit_field's field must have a type");
+			continue;
+		}
+
+		Type *type = check_type(ctx, f->type);
+		if (type_size_of(type) > 8) {
+			error(f->type, "The type of a bit_field's field must be <= 8 bytes, got %lld", cast(long long)type_size_of(type));
+		}
+
+		if (is_type_untyped(type)) {
+			gbString s = type_to_string(type);
+			error(f->type, "The type of a bit_field's field must be a typed integer, enum, or boolean, got %s", s);
+			gb_string_free(s);
+		} else if (!(is_type_integer(type) || is_type_enum(type) || is_type_boolean(type))) {
+			gbString s = type_to_string(type);
+			error(f->type, "The type of a bit_field's field must be an integer, enum, or boolean, got %s", s);
+			gb_string_free(s);
+		}
+
+		if (f->bit_size == nullptr) {
+			error(field, "A bit_field's field must have a specified bit size");
+			continue;
+		}
+
+
+		Operand o = {};
+		check_expr(ctx, &o, f->bit_size);
+		if (o.mode != Addressing_Constant) {
+			error(f->bit_size, "A bit_field's specified bit size must be a constant");
+			o.mode = Addressing_Invalid;
+		}
+		if (o.value.kind == ExactValue_Float) {
+			o.value = exact_value_to_integer(o.value);
+		}
+
+		ExactValue bit_size = o.value;
+
+		if (bit_size.kind != ExactValue_Integer) {
+			gbString s = expr_to_string(f->bit_size);
+			error(f->bit_size, "Expected an integer constant value for the specified bit size, got %s", s);
+			gb_string_free(s);
+		}
+
+		if (scope_lookup_current(ctx->scope, name) != nullptr) {
+			error(f->name, "'%.*s' is already declared in this bit_field", LIT(name));
+		} else {
+			i64 bit_size_i64 = exact_value_to_i64(bit_size);
+			u8 bit_size_u8 = 0;
+			if (bit_size_i64 <= 0) {
+				error(f->bit_size, "A bit_field's specified bit size cannot be <= 0, got %lld", cast(long long)bit_size_i64);
+				bit_size_i64 = 1;
+			}
+			if (bit_size_i64 > 64) {
+				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;
+			}
+			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;
+
+			add_entity(ctx, ctx->scope, nullptr, e);
+			array_add(&fields, e);
+			array_add(&bit_sizes, bit_size_u8);
+			add_entity_use(ctx, field, e);
+		}
+	}
+
+	GB_ASSERT(fields.count <= bf->fields.count);
+
+	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",
+		      cast(unsigned long long)total_bit_size,
+		      s,
+		      cast(unsigned long long)maximum_bit_size);
+		gb_string_free(s);
+	}
+
+	bit_field_type->BitField.fields    = slice_from_array(fields);
+	bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes);
+}
+
 gb_internal bool is_type_valid_bit_set_range(Type *t) {
 gb_internal bool is_type_valid_bit_set_range(Type *t) {
 	if (is_type_integer(t)) {
 	if (is_type_integer(t)) {
 		return true;
 		return true;
@@ -3051,6 +3189,20 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
 		return true;
 		return true;
 	case_end;
 	case_end;
 
 
+	case_ast_node(bf, BitFieldType, e);
+		bool ips = ctx->in_polymorphic_specialization;
+		defer (ctx->in_polymorphic_specialization = ips);
+		ctx->in_polymorphic_specialization = false;
+
+		*type = alloc_type_bit_field();
+		set_base_type(named_type, *type);
+		check_open_scope(ctx, e);
+		check_bit_field_type(ctx, *type, named_type, e);
+		check_close_scope(ctx);
+		(*type)->BitField.node = e;
+		return true;
+	case_end;
+
 
 
 	case_ast_node(pt, ProcType, e);
 	case_ast_node(pt, ProcType, e);
 		bool ips = ctx->in_polymorphic_specialization;
 		bool ips = ctx->in_polymorphic_specialization;

+ 18 - 0
src/checker.cpp

@@ -313,6 +313,7 @@ gb_internal void add_scope(CheckerContext *c, Ast *node, Scope *scope) {
 	case Ast_StructType:      node->StructType.scope      = scope; break;
 	case Ast_StructType:      node->StructType.scope      = scope; break;
 	case Ast_UnionType:       node->UnionType.scope       = scope; break;
 	case Ast_UnionType:       node->UnionType.scope       = scope; break;
 	case Ast_EnumType:        node->EnumType.scope        = scope; break;
 	case Ast_EnumType:        node->EnumType.scope        = scope; break;
+	case Ast_BitFieldType:    node->BitFieldType.scope    = scope; break;
 	default: GB_PANIC("Invalid node for add_scope: %.*s", LIT(ast_strings[node->kind]));
 	default: GB_PANIC("Invalid node for add_scope: %.*s", LIT(ast_strings[node->kind]));
 	}
 	}
 }
 }
@@ -334,6 +335,7 @@ gb_internal Scope *scope_of_node(Ast *node) {
 	case Ast_StructType:      return node->StructType.scope;
 	case Ast_StructType:      return node->StructType.scope;
 	case Ast_UnionType:       return node->UnionType.scope;
 	case Ast_UnionType:       return node->UnionType.scope;
 	case Ast_EnumType:        return node->EnumType.scope;
 	case Ast_EnumType:        return node->EnumType.scope;
+	case Ast_BitFieldType:    return node->BitFieldType.scope;
 	}
 	}
 	GB_PANIC("Invalid node for add_scope: %.*s", LIT(ast_strings[node->kind]));
 	GB_PANIC("Invalid node for add_scope: %.*s", LIT(ast_strings[node->kind]));
 	return nullptr;
 	return nullptr;
@@ -355,6 +357,7 @@ gb_internal void check_open_scope(CheckerContext *c, Ast *node) {
 	case Ast_EnumType:
 	case Ast_EnumType:
 	case Ast_UnionType:
 	case Ast_UnionType:
 	case Ast_BitSetType:
 	case Ast_BitSetType:
+	case Ast_BitFieldType:
 		scope->flags |= ScopeFlag_Type;
 		scope->flags |= ScopeFlag_Type;
 		break;
 		break;
 	}
 	}
@@ -2060,6 +2063,12 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
 		add_type_info_type_internal(c, bt->SoaPointer.elem);
 		add_type_info_type_internal(c, bt->SoaPointer.elem);
 		break;
 		break;
 
 
+	case Type_BitField:
+		add_type_info_type_internal(c, bt->BitField.backing_type);
+		for (Entity *f : bt->BitField.fields) {
+			add_type_info_type_internal(c, f->type);
+		}
+		break;
 
 
 	case Type_Generic:
 	case Type_Generic:
 		break;
 		break;
@@ -2309,6 +2318,13 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
 		add_min_dep_type_info(c, bt->SoaPointer.elem);
 		add_min_dep_type_info(c, bt->SoaPointer.elem);
 		break;
 		break;
 
 
+	case Type_BitField:
+		add_min_dep_type_info(c, bt->BitField.backing_type);
+		for (Entity *f : bt->BitField.fields) {
+			add_min_dep_type_info(c, f->type);
+		}
+		break;
+
 	default:
 	default:
 		GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind]));
 		GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind]));
 		break;
 		break;
@@ -2907,6 +2923,7 @@ gb_internal void init_core_type_info(Checker *c) {
 	t_type_info_relative_multi_pointer = find_core_type(c, str_lit("Type_Info_Relative_Multi_Pointer"));
 	t_type_info_relative_multi_pointer = find_core_type(c, str_lit("Type_Info_Relative_Multi_Pointer"));
 	t_type_info_matrix           = find_core_type(c, str_lit("Type_Info_Matrix"));
 	t_type_info_matrix           = find_core_type(c, str_lit("Type_Info_Matrix"));
 	t_type_info_soa_pointer      = find_core_type(c, str_lit("Type_Info_Soa_Pointer"));
 	t_type_info_soa_pointer      = find_core_type(c, str_lit("Type_Info_Soa_Pointer"));
+	t_type_info_bit_field        = find_core_type(c, str_lit("Type_Info_Bit_Field"));
 
 
 	t_type_info_named_ptr            = alloc_type_pointer(t_type_info_named);
 	t_type_info_named_ptr            = alloc_type_pointer(t_type_info_named);
 	t_type_info_integer_ptr          = alloc_type_pointer(t_type_info_integer);
 	t_type_info_integer_ptr          = alloc_type_pointer(t_type_info_integer);
@@ -2936,6 +2953,7 @@ gb_internal void init_core_type_info(Checker *c) {
 	t_type_info_relative_multi_pointer_ptr = alloc_type_pointer(t_type_info_relative_multi_pointer);
 	t_type_info_relative_multi_pointer_ptr = alloc_type_pointer(t_type_info_relative_multi_pointer);
 	t_type_info_matrix_ptr           = alloc_type_pointer(t_type_info_matrix);
 	t_type_info_matrix_ptr           = alloc_type_pointer(t_type_info_matrix);
 	t_type_info_soa_pointer_ptr      = alloc_type_pointer(t_type_info_soa_pointer);
 	t_type_info_soa_pointer_ptr      = alloc_type_pointer(t_type_info_soa_pointer);
+	t_type_info_bit_field_ptr        = alloc_type_pointer(t_type_info_bit_field);
 }
 }
 
 
 gb_internal void init_mem_allocator(Checker *c) {
 gb_internal void init_mem_allocator(Checker *c) {

+ 7 - 1
src/llvm_backend.cpp

@@ -2719,6 +2719,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
 		{ // Type info member buffer
 		{ // Type info member buffer
 			// NOTE(bill): Removes need for heap allocation by making it global memory
 			// NOTE(bill): Removes need for heap allocation by making it global memory
 			isize count = 0;
 			isize count = 0;
+			isize offsets_extra = 0;
 
 
 			for (Type *t : m->info->type_info_types) {
 			for (Type *t : m->info->type_info_types) {
 				isize index = lb_type_info_index(m->info, t, false);
 				isize index = lb_type_info_index(m->info, t, false);
@@ -2736,6 +2737,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
 				case Type_Tuple:
 				case Type_Tuple:
 					count += t->Tuple.variables.count;
 					count += t->Tuple.variables.count;
 					break;
 					break;
+				case Type_BitField:
+					count += t->BitField.fields.count;
+					// Twice is needed for the bit_offsets
+					offsets_extra += t->BitField.fields.count;
+					break;
 				}
 				}
 			}
 			}
 
 
@@ -2752,7 +2758,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
 
 
 			lb_global_type_info_member_types   = global_type_info_make(m, LB_TYPE_INFO_TYPES_NAME,   t_type_info_ptr, count);
 			lb_global_type_info_member_types   = global_type_info_make(m, LB_TYPE_INFO_TYPES_NAME,   t_type_info_ptr, count);
 			lb_global_type_info_member_names   = global_type_info_make(m, LB_TYPE_INFO_NAMES_NAME,   t_string,        count);
 			lb_global_type_info_member_names   = global_type_info_make(m, LB_TYPE_INFO_NAMES_NAME,   t_string,        count);
-			lb_global_type_info_member_offsets = global_type_info_make(m, LB_TYPE_INFO_OFFSETS_NAME, t_uintptr,       count);
+			lb_global_type_info_member_offsets = global_type_info_make(m, LB_TYPE_INFO_OFFSETS_NAME, t_uintptr,       count+offsets_extra);
 			lb_global_type_info_member_usings  = global_type_info_make(m, LB_TYPE_INFO_USINGS_NAME,  t_bool,          count);
 			lb_global_type_info_member_usings  = global_type_info_make(m, LB_TYPE_INFO_USINGS_NAME,  t_bool,          count);
 			lb_global_type_info_member_tags    = global_type_info_make(m, LB_TYPE_INFO_TAGS_NAME,    t_string,        count);
 			lb_global_type_info_member_tags    = global_type_info_make(m, LB_TYPE_INFO_TAGS_NAME,    t_string,        count);
 		}
 		}

+ 36 - 0
src/llvm_backend_debug.cpp

@@ -461,6 +461,42 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 			lb_debug_type(m, type->Matrix.elem),
 			lb_debug_type(m, type->Matrix.elem),
 			subscripts, gb_count_of(subscripts));
 			subscripts, gb_count_of(subscripts));
 	}
 	}
+
+	case Type_BitField: {
+		LLVMMetadataRef parent_scope = nullptr;
+		LLVMMetadataRef scope = nullptr;
+		LLVMMetadataRef file = nullptr;
+		unsigned line = 0;
+		u64 size_in_bits = 8*cast(u64)type_size_of(type);
+		u32 align_in_bits = 8*cast(u32)type_align_of(type);
+		LLVMDIFlags flags = LLVMDIFlagZero;
+
+		unsigned element_count = cast(unsigned)type->BitField.fields.count;
+		LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count);
+
+		u64 offset_in_bits = 0;
+		for (unsigned i = 0; i < element_count; i++) {
+			Entity *f = type->BitField.fields[i];
+			u8 bit_size = type->BitField.bit_sizes[i];
+			GB_ASSERT(f->kind == Entity_Variable);
+			String name = f->token.string;
+			unsigned field_line = 0;
+			LLVMDIFlags field_flags = LLVMDIFlagZero;
+			elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, field_line,
+				bit_size, offset_in_bits, offset_in_bits,
+				field_flags, lb_debug_type(m, f->type)
+			);
+
+			offset_in_bits += bit_size;
+		}
+
+
+		return LLVMDIBuilderCreateStructType(m->debug_builder, parent_scope, "", 0, file, line,
+			size_in_bits, align_in_bits, flags,
+			nullptr, elements, element_count, 0, nullptr,
+			"", 0
+		);
+	}
 	}
 	}
 
 
 	GB_PANIC("Invalid type %s", type_to_string(type));
 	GB_PANIC("Invalid type %s", type_to_string(type));

+ 3 - 1
src/llvm_backend_general.cpp

@@ -2216,7 +2216,9 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 			}
 			}
 			return LLVMStructTypeInContext(ctx, fields, field_count, false);
 			return LLVMStructTypeInContext(ctx, fields, field_count, false);
 		}
 		}
-	
+
+	case Type_BitField:
+		return lb_type_internal(m, type->BitField.backing_type);
 	}
 	}
 
 
 	GB_PANIC("Invalid type %s", type_to_string(type));
 	GB_PANIC("Invalid type %s", type_to_string(type));

+ 67 - 0
src/llvm_backend_type.cpp

@@ -1788,6 +1788,73 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup
 				lb_emit_store(p, tag, res);
 				lb_emit_store(p, tag, res);
 			}
 			}
 			break;
 			break;
+
+		case Type_BitField:
+			{
+				tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_bit_field_ptr);
+				LLVMValueRef vals[5] = {};
+
+				vals[0] = lb_type_info(m, t->BitField.backing_type).value;
+				isize count = t->BitField.fields.count;
+				if (count > 0) {
+					i64 names_offset   = 0;
+					i64 types_offset   = 0;
+					i64 bit_sizes_offset = 0;
+					i64 bit_offsets_offset = 0;
+					lbValue memory_names       = lb_type_info_member_names_offset  (m, count, &names_offset);
+					lbValue memory_types       = lb_type_info_member_types_offset  (m, count, &types_offset);
+					lbValue memory_bit_sizes   = lb_type_info_member_offsets_offset(m, count, &bit_sizes_offset);
+					lbValue memory_bit_offsets = lb_type_info_member_offsets_offset(m, count, &bit_offsets_offset);
+
+					u64 bit_offset = 0;
+					for (isize source_index = 0; source_index < count; source_index++) {
+						Entity *f = t->BitField.fields[source_index];
+						u64 bit_size = cast(u64)t->BitField.bit_sizes[source_index];
+
+						lbValue index = lb_const_int(m, t_int, source_index);
+						if (f->token.string.len > 0) {
+							lbValue name = lb_emit_ptr_offset(p, memory_names, index);
+							lb_emit_store(p, name, lb_const_string(m, f->token.string));
+						}
+						lbValue type_ptr       = lb_emit_ptr_offset(p, memory_types, index);
+						lbValue bit_size_ptr   = lb_emit_ptr_offset(p, memory_bit_sizes, index);
+						lbValue bit_offset_ptr = lb_emit_ptr_offset(p, memory_bit_offsets, index);
+
+						lb_emit_store(p, type_ptr,       lb_type_info(m, f->type));
+						lb_emit_store(p, bit_size_ptr,   lb_const_int(m, t_uintptr, bit_size));
+						lb_emit_store(p, bit_offset_ptr, lb_const_int(m, t_uintptr, bit_offset));
+
+						// lb_global_type_info_member_types_values  [types_offset      +source_index] = get_type_info_ptr(m, f->type);
+						// lb_global_type_info_member_offsets_values[bit_sizes_offset  +source_index] = lb_const_int(m, t_uintptr, bit_size).value;
+						// lb_global_type_info_member_offsets_values[bit_offsets_offset+source_index] = lb_const_int(m, t_uintptr, bit_offset).value;
+						// if (f->token.string.len > 0) {
+						// 	lb_global_type_info_member_names_values[names_offset+source_index] = lb_const_string(m, f->token.string).value;
+						// }
+
+						bit_offset += bit_size;
+					}
+
+					lbValue cv = lb_const_int(m, t_int, count);
+					vals[1] = llvm_const_slice(m, memory_names,   cv);
+					vals[2] = llvm_const_slice(m, memory_types,   cv);
+					vals[3] = llvm_const_slice(m, memory_bit_sizes, cv);
+					vals[4] = llvm_const_slice(m, memory_bit_offsets, cv);
+				}
+
+				for (isize i = 0; i < gb_count_of(vals); i++) {
+					if (vals[i] == nullptr) {
+						vals[i]  = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i)));
+					}
+				}
+
+				lbValue res = {};
+				res.type = type_deref(tag.type);
+				res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
+				lb_emit_store(p, tag, res);
+
+				break;
+			}
+
 		}
 		}
 
 
 
 

+ 78 - 0
src/parser.cpp

@@ -350,6 +350,11 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
 		n->Field.names = clone_ast_array(n->Field.names, f);
 		n->Field.names = clone_ast_array(n->Field.names, f);
 		n->Field.type  = clone_ast(n->Field.type, f);
 		n->Field.type  = clone_ast(n->Field.type, f);
 		break;
 		break;
+	case Ast_BitFieldField:
+		n->BitFieldField.name     = clone_ast(n->BitFieldField.name, f);
+		n->BitFieldField.type     = clone_ast(n->BitFieldField.type, f);
+		n->BitFieldField.bit_size = clone_ast(n->BitFieldField.bit_size, f);
+		break;
 	case Ast_FieldList:
 	case Ast_FieldList:
 		n->FieldList.list = clone_ast_array(n->FieldList.list, f);
 		n->FieldList.list = clone_ast_array(n->FieldList.list, f);
 		break;
 		break;
@@ -406,6 +411,10 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
 		n->BitSetType.elem       = clone_ast(n->BitSetType.elem, f);
 		n->BitSetType.elem       = clone_ast(n->BitSetType.elem, f);
 		n->BitSetType.underlying = clone_ast(n->BitSetType.underlying, f);
 		n->BitSetType.underlying = clone_ast(n->BitSetType.underlying, f);
 		break;
 		break;
+	case Ast_BitFieldType:
+		n->BitFieldType.backing_type = clone_ast(n->BitFieldType.backing_type, f);
+		n->BitFieldType.fields = clone_ast_array(n->BitFieldType.fields, f);
+		break;
 	case Ast_MapType:
 	case Ast_MapType:
 		n->MapType.count = clone_ast(n->MapType.count, f);
 		n->MapType.count = clone_ast(n->MapType.count, f);
 		n->MapType.key   = clone_ast(n->MapType.key, f);
 		n->MapType.key   = clone_ast(n->MapType.key, f);
@@ -1045,6 +1054,17 @@ gb_internal Ast *ast_field(AstFile *f, Array<Ast *> const &names, Ast *type, Ast
 	return result;
 	return result;
 }
 }
 
 
+gb_internal Ast *ast_bit_field_field(AstFile *f, Ast *name, Ast *type, Ast *bit_size,
+                                     CommentGroup *docs, CommentGroup *comment) {
+	Ast *result = alloc_ast_node(f, Ast_BitFieldField);
+	result->BitFieldField.name     = name;
+	result->BitFieldField.type     = type;
+	result->BitFieldField.bit_size = bit_size;
+	result->BitFieldField.docs     = docs;
+	result->BitFieldField.comment  = comment;
+	return result;
+}
+
 gb_internal Ast *ast_field_list(AstFile *f, Token token, Array<Ast *> const &list) {
 gb_internal Ast *ast_field_list(AstFile *f, Token token, Array<Ast *> const &list) {
 	Ast *result = alloc_ast_node(f, Ast_FieldList);
 	Ast *result = alloc_ast_node(f, Ast_FieldList);
 	result->FieldList.token = token;
 	result->FieldList.token = token;
@@ -1178,6 +1198,17 @@ gb_internal Ast *ast_bit_set_type(AstFile *f, Token token, Ast *elem, Ast *under
 	return result;
 	return result;
 }
 }
 
 
+gb_internal Ast *ast_bit_field_type(AstFile *f, Token token, Ast *backing_type, Token open, Array<Ast *> const &fields, Token close) {
+	Ast *result = alloc_ast_node(f, Ast_BitFieldType);
+	result->BitFieldType.token        = token;
+	result->BitFieldType.backing_type = backing_type;
+	result->BitFieldType.open         = open;
+	result->BitFieldType.fields       = slice_from_array(fields);
+	result->BitFieldType.close        = close;
+	return result;
+}
+
+
 gb_internal Ast *ast_map_type(AstFile *f, Token token, Ast *key, Ast *value) {
 gb_internal Ast *ast_map_type(AstFile *f, Token token, Ast *key, Ast *value) {
 	Ast *result = alloc_ast_node(f, Ast_MapType);
 	Ast *result = alloc_ast_node(f, Ast_MapType);
 	result->MapType.token = token;
 	result->MapType.token = token;
@@ -2549,6 +2580,53 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
 		return ast_matrix_type(f, token, row_count, column_count, type);
 		return ast_matrix_type(f, token, row_count, column_count, type);
 	} break;
 	} break;
 
 
+	case Token_bit_field: {
+		Token token = expect_token(f, Token_bit_field);
+		isize prev_level;
+
+		prev_level = f->expr_level;
+		f->expr_level = -1;
+
+		Ast *backing_type = parse_type_or_ident(f);
+		if (backing_type == nullptr) {
+			Token token = advance_token(f);
+			syntax_error(token, "Expected a backing type for a 'bit_field'");
+			backing_type = ast_bad_expr(f, token, f->curr_token);
+		}
+
+		skip_possible_newline_for_literal(f);
+		Token open = expect_token_after(f, Token_OpenBrace, "bit_field");
+
+
+		auto fields = array_make<Ast *>(ast_allocator(f), 0, 0);
+
+		while (f->curr_token.kind != Token_CloseBrace &&
+		       f->curr_token.kind != Token_EOF) {
+			CommentGroup *docs = nullptr;
+			CommentGroup *comment = nullptr;
+
+			Ast *name = parse_ident(f);
+			expect_token(f, Token_Colon);
+			Ast *type = parse_type(f);
+			expect_token(f, Token_Or);
+			Ast *bit_size = parse_expr(f, true);
+
+			Ast *bf_field = ast_bit_field_field(f, name, type, bit_size, docs, comment);
+			array_add(&fields, bf_field);
+
+			if (!allow_field_separator(f)) {
+				break;
+			}
+		}
+
+		Token close = expect_closing_brace_of_field_list(f);
+
+		f->expr_level = prev_level;
+
+		return ast_bit_field_type(f, token, backing_type, open, fields, close);
+	}
+
+
 	case Token_struct: {
 	case Token_struct: {
 		Token    token = expect_token(f, Token_struct);
 		Token    token = expect_token(f, Token_struct);
 		Ast *polymorphic_params = nullptr;
 		Ast *polymorphic_params = nullptr;

+ 15 - 0
src/parser.hpp

@@ -650,6 +650,13 @@ AST_KIND(_DeclEnd,   "", bool) \
 		CommentGroup *   docs;      \
 		CommentGroup *   docs;      \
 		CommentGroup *   comment;   \
 		CommentGroup *   comment;   \
 	}) \
 	}) \
+	AST_KIND(BitFieldField, "bit field field", struct { \
+		Ast *         name;     \
+		Ast *         type;     \
+		Ast *         bit_size; \
+		CommentGroup *docs;     \
+		CommentGroup *comment;  \
+	}) \
 	AST_KIND(FieldList, "field list", struct { \
 	AST_KIND(FieldList, "field list", struct { \
 		Token token;       \
 		Token token;       \
 		Slice<Ast *> list; \
 		Slice<Ast *> list; \
@@ -742,6 +749,14 @@ AST_KIND(_TypeBegin, "", bool) \
 		Ast * elem;  \
 		Ast * elem;  \
 		Ast * underlying; \
 		Ast * underlying; \
 	}) \
 	}) \
+	AST_KIND(BitFieldType, "bit field type", struct { \
+		Scope *scope; \
+		Token token; \
+		Ast * backing_type;  \
+		Token open; \
+		Slice<Ast *> fields; /* BitFieldField */ \
+		Token close; \
+	}) \
 	AST_KIND(MapType, "map type", struct { \
 	AST_KIND(MapType, "map type", struct { \
 		Token token; \
 		Token token; \
 		Ast *count; \
 		Ast *count; \

+ 3 - 0
src/parser_pos.cpp

@@ -111,6 +111,7 @@ gb_internal Token ast_token(Ast *node) {
 	case Ast_UnionType:        return node->UnionType.token;
 	case Ast_UnionType:        return node->UnionType.token;
 	case Ast_EnumType:         return node->EnumType.token;
 	case Ast_EnumType:         return node->EnumType.token;
 	case Ast_BitSetType:       return node->BitSetType.token;
 	case Ast_BitSetType:       return node->BitSetType.token;
+	case Ast_BitFieldType:     return node->BitFieldType.token;
 	case Ast_MapType:          return node->MapType.token;
 	case Ast_MapType:          return node->MapType.token;
 	case Ast_MatrixType:       return node->MatrixType.token;
 	case Ast_MatrixType:       return node->MatrixType.token;
 	}
 	}
@@ -364,6 +365,8 @@ Token ast_end_token(Ast *node) {
 			return ast_end_token(node->BitSetType.underlying);
 			return ast_end_token(node->BitSetType.underlying);
 		}
 		}
 		return ast_end_token(node->BitSetType.elem);
 		return ast_end_token(node->BitSetType.elem);
+	case Ast_BitFieldType:
+		return node->BitFieldType.close;
 	case Ast_MapType:          return ast_end_token(node->MapType.value);
 	case Ast_MapType:          return ast_end_token(node->MapType.value);
 	case Ast_MatrixType:       return ast_end_token(node->MatrixType.elem);
 	case Ast_MatrixType:       return ast_end_token(node->MatrixType.elem);
 	}
 	}

+ 24 - 0
src/types.cpp

@@ -282,6 +282,13 @@ struct TypeProc {
 		Type *generic_column_count;                       \
 		Type *generic_column_count;                       \
 		i64   stride_in_bytes;                            \
 		i64   stride_in_bytes;                            \
 	})                                                        \
 	})                                                        \
+	TYPE_KIND(BitField, struct {                              \
+		Scope *         scope;                            \
+		Type *          backing_type;                     \
+		Slice<Entity *> fields;                           \
+		Slice<u8>       bit_sizes;                        \
+		Ast *           node;                             \
+	})                                                        \
 	TYPE_KIND(SoaPointer, struct { Type *elem; })
 	TYPE_KIND(SoaPointer, struct { Type *elem; })
 
 
 
 
@@ -355,6 +362,7 @@ enum Typeid_Kind : u8 {
 	Typeid_Relative_Multi_Pointer,
 	Typeid_Relative_Multi_Pointer,
 	Typeid_Matrix,
 	Typeid_Matrix,
 	Typeid_SoaPointer,
 	Typeid_SoaPointer,
+	Typeid_Bit_Field,
 };
 };
 
 
 // IMPORTANT NOTE(bill): This must match the same as the in core.odin
 // IMPORTANT NOTE(bill): This must match the same as the in core.odin
@@ -641,6 +649,7 @@ gb_global Type *t_type_info_relative_pointer     = nullptr;
 gb_global Type *t_type_info_relative_multi_pointer = nullptr;
 gb_global Type *t_type_info_relative_multi_pointer = nullptr;
 gb_global Type *t_type_info_matrix               = nullptr;
 gb_global Type *t_type_info_matrix               = nullptr;
 gb_global Type *t_type_info_soa_pointer          = nullptr;
 gb_global Type *t_type_info_soa_pointer          = nullptr;
+gb_global Type *t_type_info_bit_field            = nullptr;
 
 
 gb_global Type *t_type_info_named_ptr            = nullptr;
 gb_global Type *t_type_info_named_ptr            = nullptr;
 gb_global Type *t_type_info_integer_ptr          = nullptr;
 gb_global Type *t_type_info_integer_ptr          = nullptr;
@@ -670,6 +679,7 @@ gb_global Type *t_type_info_relative_pointer_ptr = nullptr;
 gb_global Type *t_type_info_relative_multi_pointer_ptr = nullptr;
 gb_global Type *t_type_info_relative_multi_pointer_ptr = nullptr;
 gb_global Type *t_type_info_matrix_ptr           = nullptr;
 gb_global Type *t_type_info_matrix_ptr           = nullptr;
 gb_global Type *t_type_info_soa_pointer_ptr      = nullptr;
 gb_global Type *t_type_info_soa_pointer_ptr      = nullptr;
+gb_global Type *t_type_info_bit_field_ptr        = nullptr;
 
 
 gb_global Type *t_allocator                      = nullptr;
 gb_global Type *t_allocator                      = nullptr;
 gb_global Type *t_allocator_ptr                  = nullptr;
 gb_global Type *t_allocator_ptr                  = nullptr;
@@ -1040,6 +1050,11 @@ gb_internal Type *alloc_type_enum() {
 	return t;
 	return t;
 }
 }
 
 
+gb_internal Type *alloc_type_bit_field() {
+	Type *t = alloc_type(Type_BitField);
+	return t;
+}
+
 gb_internal Type *alloc_type_relative_pointer(Type *pointer_type, Type *base_integer) {
 gb_internal Type *alloc_type_relative_pointer(Type *pointer_type, Type *base_integer) {
 	GB_ASSERT(is_type_pointer(pointer_type));
 	GB_ASSERT(is_type_pointer(pointer_type));
 	GB_ASSERT(is_type_integer(base_integer));
 	GB_ASSERT(is_type_integer(base_integer));
@@ -1707,6 +1722,10 @@ gb_internal bool is_type_bit_set(Type *t) {
 	t = base_type(t);
 	t = base_type(t);
 	return (t->kind == Type_BitSet);
 	return (t->kind == Type_BitSet);
 }
 }
+gb_internal bool is_type_bit_field(Type *t) {
+	t = base_type(t);
+	return (t->kind == Type_BitField);
+}
 gb_internal bool is_type_map(Type *t) {
 gb_internal bool is_type_map(Type *t) {
 	t = base_type(t);
 	t = base_type(t);
 	return t->kind == Type_Map;
 	return t->kind == Type_Map;
@@ -3568,6 +3587,8 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
 	case Type_Slice:
 	case Type_Slice:
 		return build_context.int_size;
 		return build_context.int_size;
 
 
+	case Type_BitField:
+		return type_align_of_internal(t->BitField.backing_type, path);
 
 
 	case Type_Tuple: {
 	case Type_Tuple: {
 		i64 max = 1;
 		i64 max = 1;
@@ -3943,6 +3964,9 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
 		return stride_in_bytes * t->Matrix.column_count;
 		return stride_in_bytes * t->Matrix.column_count;
 	}
 	}
 
 
+	case Type_BitField:
+		return type_size_of_internal(t->BitField.backing_type, path);
+
 	case Type_RelativePointer:
 	case Type_RelativePointer:
 		return type_size_of_internal(t->RelativePointer.base_integer, path);
 		return type_size_of_internal(t->RelativePointer.base_integer, path);
 	case Type_RelativeMultiPointer:
 	case Type_RelativeMultiPointer: