| author | |
| committer | |
| log | fc5d47b9b960aa08d65bf0dfe3d6395c811f793b |
| tree | 2ccc51b0a0f2429793c4be5075bfda53b1b01b65 |
| parent | 4b5cc80f665314067e0e5b96c859acca1b2e1cb0 |
See #261
Still need to do:
* reading a field that has bit offset 0 but still needs to
shift and truncate
* writing a field6 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 | }; |
| 856 | 857 | ||
| 857 | struct TypeTableEntryInt { | 858 | struct 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 | } |
| 262 | 262 | ||
| 263 | // This has to do with packed structs | 263 | // This has to do with packed structs |
| 264 | static uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) { | 264 | uint64_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); |
| 266 | 266 | ||
| 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 | } |
| 288 | 288 | ||
| 289 | TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const, | 289 | TypeTableEntry *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); |
| 293 | 293 | ||
| ... | @@ -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 | } | ||
| 320 | 325 | ||
| 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; | ||
| 341 | 347 | ||
| 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 |
| 16 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); | 16 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); |
| 17 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); | 17 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); |
| 18 | TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const, | 18 | TypeTableEntry *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); |
| 20 | bool is_node_void_expr(AstNode *node); | 20 | bool is_node_void_expr(AstNode *node); |
| 21 | uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry); | 21 | uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry); |
| 22 | uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry); | ||
| 22 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint8_t size_in_bits); | 23 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint8_t size_in_bits); |
| 23 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint8_t size_in_bits); | 24 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint8_t size_in_bits); |
| 24 | TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); | 25 | TypeTableEntry **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, |
| 1379 | 1379 | ||
| 1380 | static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) { | 1380 | static 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 | } |
| 1391 | 1408 | ||
| 1392 | static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) { | 1409 | static 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 | |||
| 230 | const u2 = @intType(false, 2); | ||
| 231 | const u3 = @intType(false, 3); | ||
| 232 | |||
| 233 | const BitField1 = packed struct { | ||
| 234 | a: u3, | ||
| 235 | b: u3, | ||
| 236 | c: u2, | ||
| 237 | }; | ||
| 238 | |||
| 239 | fn 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 | |||
| 252 | fn getB(data: &const BitField1) -> u3 { | ||
| 253 | return data.b; | ||
| 254 | } | ||
| 255 | |||
| 256 | fn getC(data: &const BitField1) -> u2 { | ||
| 257 | return data.c; | ||
| 258 | } |