Commit fc5d47b9b9
Changed files (6)
src/all_types.hpp
@@ -852,6 +852,7 @@ struct TypeTableEntryPointer {
TypeTableEntry *child_type;
bool is_const;
bool is_volatile;
+ uint32_t bit_offset;
};
struct TypeTableEntryInt {
@@ -1202,7 +1203,7 @@ struct TypeId {
TypeTableEntry *child_type;
bool is_const;
bool is_volatile;
- uint8_t bit_offset;
+ uint32_t bit_offset;
} pointer;
struct {
TypeTableEntry *child_type;
src/analyze.cpp
@@ -261,7 +261,7 @@ uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
}
// This has to do with packed structs
-static uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
+uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
TypeTableEntry *canon_type = get_underlying_type(type_entry);
if (!type_has_bits(type_entry))
@@ -287,7 +287,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
}
TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
- uint8_t bit_offset, bool is_volatile)
+ uint32_t bit_offset, bool is_volatile)
{
assert(child_type->id != TypeTableEntryIdInvalid);
@@ -316,7 +316,12 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
const char *const_str = is_const ? "const " : "";
const char *volatile_str = is_volatile ? "volatile " : "";
buf_resize(&entry->name, 0);
- buf_appendf(&entry->name, "&%s%s%s", const_str, volatile_str, buf_ptr(&child_type->name));
+ if (bit_offset == 0) {
+ buf_appendf(&entry->name, "&%s%s%s", const_str, volatile_str, buf_ptr(&child_type->name));
+ } else {
+ buf_appendf(&entry->name, "&:%" PRIu8 " %s%s%s", bit_offset, const_str,
+ volatile_str, buf_ptr(&child_type->name));
+ }
TypeTableEntry *canon_child_type = get_underlying_type(child_type);
assert(canon_child_type->id != TypeTableEntryIdInvalid);
@@ -338,6 +343,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
entry->data.pointer.child_type = child_type;
entry->data.pointer.is_const = is_const;
entry->data.pointer.is_volatile = is_volatile;
+ entry->data.pointer.bit_offset = bit_offset;
if (parent_pointer) {
*parent_pointer = entry;
src/analyze.hpp
@@ -16,9 +16,10 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *m
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
- uint8_t bit_offset, bool is_volatile);
+ uint32_t bit_offset, bool is_volatile);
bool is_node_void_expr(AstNode *node);
uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
+uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry);
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint8_t size_in_bits);
TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint8_t size_in_bits);
TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
src/codegen.cpp
@@ -1379,14 +1379,31 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) {
TypeTableEntry *child_type = instruction->base.value.type;
- if (!type_has_bits(child_type)) {
+ if (!type_has_bits(child_type))
return nullptr;
- }
+
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
TypeTableEntry *ptr_type = instruction->ptr->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
bool is_volatile = ptr_type->data.pointer.is_volatile;
- return get_handle_value(g, ptr, child_type, is_volatile);
+
+ uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
+ if (bit_offset == 0)
+ return get_handle_value(g, ptr, child_type, is_volatile);
+
+ assert(!handle_is_ptr(child_type));
+
+ LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, "");
+ LLVMSetVolatile(containing_int, is_volatile);
+
+ uint32_t child_bit_count = type_size_bits(g, child_type);
+ uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
+ uint32_t shift_amt = host_bit_count - bit_offset - child_bit_count;
+
+ LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
+ LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
+
+ return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
}
static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
src/ir.cpp
@@ -9067,7 +9067,8 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
}
}
ir_build_struct_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
- return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, 0, is_volatile);
+ return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const,
+ field->packed_bits_offset, is_volatile);
} else {
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
field_ptr_instruction, container_ptr, container_type);
test/cases/struct.zig
@@ -225,3 +225,34 @@ fn packedStruct() {
const four = foo.x + foo.y;
assert(four == 4);
}
+
+
+const u2 = @intType(false, 2);
+const u3 = @intType(false, 3);
+
+const BitField1 = packed struct {
+ a: u3,
+ b: u3,
+ c: u2,
+};
+
+fn bitFieldAccess() {
+ @setFnTest(this);
+
+ const data = BitField1 {
+ .a = 1,
+ .b = 2,
+ .c = 3,
+ };
+ assert(getB(&data) == 2);
+ assert(getC(&data) == 3);
+ comptime assert(@sizeOf(BitField1) == 1);
+}
+
+fn getB(data: &const BitField1) -> u3 {
+ return data.b;
+}
+
+fn getC(data: &const BitField1) -> u2 {
+ return data.c;
+}