diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-02-16 15:45:41 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-02-16 15:45:41 -0500 |
| commit | fc5d47b9b960aa08d65bf0dfe3d6395c811f793b (patch) | |
| tree | 2ccc51b0a0f2429793c4be5075bfda53b1b01b65 | |
| parent | 4b5cc80f665314067e0e5b96c859acca1b2e1cb0 (diff) | |
| download | zig-fc5d47b9b960aa08d65bf0dfe3d6395c811f793b.tar.gz zig-fc5d47b9b960aa08d65bf0dfe3d6395c811f793b.zip | |
reading from a bit field partially works
See #261
Still need to do:
* reading a field that has bit offset 0 but still needs to
shift and truncate
* writing a field
| -rw-r--r-- | src/all_types.hpp | 3 | ||||
| -rw-r--r-- | src/analyze.cpp | 12 | ||||
| -rw-r--r-- | src/analyze.hpp | 3 | ||||
| -rw-r--r-- | src/codegen.cpp | 23 | ||||
| -rw-r--r-- | src/ir.cpp | 3 | ||||
| -rw-r--r-- | test/cases/struct.zig | 31 |
6 files changed, 66 insertions, 9 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index 97e6076b51..d869f2d437 100644 --- a/src/all_types.hpp +++ b/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; diff --git a/src/analyze.cpp b/src/analyze.cpp index 88337a4959..1b248ba128 100644 --- a/src/analyze.cpp +++ b/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; diff --git a/src/analyze.hpp b/src/analyze.hpp index 1214468940..4cdcea556f 100644 --- a/src/analyze.hpp +++ b/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); diff --git a/src/codegen.cpp b/src/codegen.cpp index 8180034956..0d8ef0b03a 100644 --- a/src/codegen.cpp +++ b/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) { diff --git a/src/ir.cpp b/src/ir.cpp index 03b77a69f7..ddb2164ad5 100644 --- a/src/ir.cpp +++ b/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); diff --git a/test/cases/struct.zig b/test/cases/struct.zig index fd49d00f76..403133e369 100644 --- a/test/cases/struct.zig +++ b/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; +} |
