authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-16 15:45:41-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-16 15:45:41-05:00
logfc5d47b9b960aa08d65bf0dfe3d6395c811f793b
tree2ccc51b0a0f2429793c4be5075bfda53b1b01b65
parent4b5cc80f665314067e0e5b96c859acca1b2e1cb0

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

6 files changed, 66 insertions(+), 9 deletions(-)

src/all_types.hpp+2-1
...@@ -852,6 +852,7 @@ struct TypeTableEntryPointer {...@@ -852,6 +852,7 @@ struct TypeTableEntryPointer {
852 TypeTableEntry *child_type;852 TypeTableEntry *child_type;
853 bool is_const;853 bool is_const;
854 bool is_volatile;854 bool is_volatile;
855 uint32_t bit_offset;
855};856};
856857
857struct TypeTableEntryInt {858struct TypeTableEntryInt {
...@@ -1202,7 +1203,7 @@ struct TypeId {...@@ -1202,7 +1203,7 @@ struct TypeId {
1202 TypeTableEntry *child_type;1203 TypeTableEntry *child_type;
1203 bool is_const;1204 bool is_const;
1204 bool is_volatile;1205 bool is_volatile;
1205 uint8_t bit_offset;1206 uint32_t bit_offset;
1206 } pointer;1207 } pointer;
1207 struct {1208 struct {
1208 TypeTableEntry *child_type;1209 TypeTableEntry *child_type;
src/analyze.cpp+9-3
...@@ -261,7 +261,7 @@ uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {...@@ -261,7 +261,7 @@ uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
261}261}
262262
263// This has to do with packed structs263// This has to do with packed structs
264static uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {264uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
265 TypeTableEntry *canon_type = get_underlying_type(type_entry);265 TypeTableEntry *canon_type = get_underlying_type(type_entry);
266266
267 if (!type_has_bits(type_entry))267 if (!type_has_bits(type_entry))
...@@ -287,7 +287,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {...@@ -287,7 +287,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
287}287}
288288
289TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,289TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
290 uint8_t bit_offset, bool is_volatile)290 uint32_t bit_offset, bool is_volatile)
291{291{
292 assert(child_type->id != TypeTableEntryIdInvalid);292 assert(child_type->id != TypeTableEntryIdInvalid);
293293
...@@ -316,7 +316,12 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type...@@ -316,7 +316,12 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
316 const char *const_str = is_const ? "const " : "";316 const char *const_str = is_const ? "const " : "";
317 const char *volatile_str = is_volatile ? "volatile " : "";317 const char *volatile_str = is_volatile ? "volatile " : "";
318 buf_resize(&entry->name, 0);318 buf_resize(&entry->name, 0);
319 buf_appendf(&entry->name, "&%s%s%s", const_str, volatile_str, buf_ptr(&child_type->name));319 if (bit_offset == 0) {
320 buf_appendf(&entry->name, "&%s%s%s", const_str, volatile_str, buf_ptr(&child_type->name));
321 } else {
322 buf_appendf(&entry->name, "&:%" PRIu8 " %s%s%s", bit_offset, const_str,
323 volatile_str, buf_ptr(&child_type->name));
324 }
320325
321 TypeTableEntry *canon_child_type = get_underlying_type(child_type);326 TypeTableEntry *canon_child_type = get_underlying_type(child_type);
322 assert(canon_child_type->id != TypeTableEntryIdInvalid);327 assert(canon_child_type->id != TypeTableEntryIdInvalid);
...@@ -338,6 +343,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type...@@ -338,6 +343,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
338 entry->data.pointer.child_type = child_type;343 entry->data.pointer.child_type = child_type;
339 entry->data.pointer.is_const = is_const;344 entry->data.pointer.is_const = is_const;
340 entry->data.pointer.is_volatile = is_volatile;345 entry->data.pointer.is_volatile = is_volatile;
346 entry->data.pointer.bit_offset = bit_offset;
341347
342 if (parent_pointer) {348 if (parent_pointer) {
343 *parent_pointer = entry;349 *parent_pointer = entry;
src/analyze.hpp+2-1
...@@ -16,9 +16,10 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *m...@@ -16,9 +16,10 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *m
16TypeTableEntry *new_type_table_entry(TypeTableEntryId id);16TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
17TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);17TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
18TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,18TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
19 uint8_t bit_offset, bool is_volatile);19 uint32_t bit_offset, bool is_volatile);
20bool is_node_void_expr(AstNode *node);20bool is_node_void_expr(AstNode *node);
21uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);21uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
22uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry);
22TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint8_t size_in_bits);23TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint8_t size_in_bits);
23TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint8_t size_in_bits);24TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint8_t size_in_bits);
24TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);25TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
src/codegen.cpp+20-3
...@@ -1379,14 +1379,31 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,...@@ -1379,14 +1379,31 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
13791379
1380static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) {1380static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) {
1381 TypeTableEntry *child_type = instruction->base.value.type;1381 TypeTableEntry *child_type = instruction->base.value.type;
1382 if (!type_has_bits(child_type)) {1382 if (!type_has_bits(child_type))
1383 return nullptr;1383 return nullptr;
1384 }1384
1385 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);1385 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
1386 TypeTableEntry *ptr_type = instruction->ptr->value.type;1386 TypeTableEntry *ptr_type = instruction->ptr->value.type;
1387 assert(ptr_type->id == TypeTableEntryIdPointer);1387 assert(ptr_type->id == TypeTableEntryIdPointer);
1388 bool is_volatile = ptr_type->data.pointer.is_volatile;1388 bool is_volatile = ptr_type->data.pointer.is_volatile;
1389 return get_handle_value(g, ptr, child_type, is_volatile);1389
1390 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
1391 if (bit_offset == 0)
1392 return get_handle_value(g, ptr, child_type, is_volatile);
1393
1394 assert(!handle_is_ptr(child_type));
1395
1396 LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, "");
1397 LLVMSetVolatile(containing_int, is_volatile);
1398
1399 uint32_t child_bit_count = type_size_bits(g, child_type);
1400 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
1401 uint32_t shift_amt = host_bit_count - bit_offset - child_bit_count;
1402
1403 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
1404 LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
1405
1406 return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
1390}1407}
13911408
1392static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {1409static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
src/ir.cpp+2-1
...@@ -9067,7 +9067,8 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field...@@ -9067,7 +9067,8 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
9067 }9067 }
9068 }9068 }
9069 ir_build_struct_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);9069 ir_build_struct_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
9070 return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, 0, is_volatile);9070 return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const,
9071 field->packed_bits_offset, is_volatile);
9071 } else {9072 } else {
9072 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,9073 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
9073 field_ptr_instruction, container_ptr, container_type);9074 field_ptr_instruction, container_ptr, container_type);
test/cases/struct.zig+31
...@@ -225,3 +225,34 @@ fn packedStruct() {...@@ -225,3 +225,34 @@ fn packedStruct() {
225 const four = foo.x + foo.y;225 const four = foo.x + foo.y;
226 assert(four == 4);226 assert(four == 4);
227}227}
228
229
230const u2 = @intType(false, 2);
231const u3 = @intType(false, 3);
232
233const BitField1 = packed struct {
234 a: u3,
235 b: u3,
236 c: u2,
237};
238
239fn bitFieldAccess() {
240 @setFnTest(this);
241
242 const data = BitField1 {
243 .a = 1,
244 .b = 2,
245 .c = 3,
246 };
247 assert(getB(&data) == 2);
248 assert(getC(&data) == 3);
249 comptime assert(@sizeOf(BitField1) == 1);
250}
251
252fn getB(data: &const BitField1) -> u3 {
253 return data.b;
254}
255
256fn getC(data: &const BitField1) -> u2 {
257 return data.c;
258}