| 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 | 852 | TypeTableEntry *child_type; |
| 853 | 853 | bool is_const; |
| 854 | 854 | bool is_volatile; |
| 855 | uint32_t bit_offset; | |
| 855 | 856 | }; |
| 856 | 857 | |
| 857 | 858 | struct TypeTableEntryInt { |
| ... | ... | @@ -1202,7 +1203,7 @@ struct TypeId { |
| 1202 | 1203 | TypeTableEntry *child_type; |
| 1203 | 1204 | bool is_const; |
| 1204 | 1205 | bool is_volatile; |
| 1205 | uint8_t bit_offset; | |
| 1206 | uint32_t bit_offset; | |
| 1206 | 1207 | } pointer; |
| 1207 | 1208 | struct { |
| 1208 | 1209 | TypeTableEntry *child_type; |
src/analyze.cpp+9-3| ... | ... | @@ -261,7 +261,7 @@ uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) { |
| 261 | 261 | } |
| 262 | 262 | |
| 263 | 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 | 265 | TypeTableEntry *canon_type = get_underlying_type(type_entry); |
| 266 | 266 | |
| 267 | 267 | if (!type_has_bits(type_entry)) |
| ... | ... | @@ -287,7 +287,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { |
| 287 | 287 | } |
| 288 | 288 | |
| 289 | 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 | 292 | assert(child_type->id != TypeTableEntryIdInvalid); |
| 293 | 293 | |
| ... | ... | @@ -316,7 +316,12 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type |
| 316 | 316 | const char *const_str = is_const ? "const " : ""; |
| 317 | 317 | const char *volatile_str = is_volatile ? "volatile " : ""; |
| 318 | 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 | 326 | TypeTableEntry *canon_child_type = get_underlying_type(child_type); |
| 322 | 327 | assert(canon_child_type->id != TypeTableEntryIdInvalid); |
| ... | ... | @@ -338,6 +343,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type |
| 338 | 343 | entry->data.pointer.child_type = child_type; |
| 339 | 344 | entry->data.pointer.is_const = is_const; |
| 340 | 345 | entry->data.pointer.is_volatile = is_volatile; |
| 346 | entry->data.pointer.bit_offset = bit_offset; | |
| 341 | 347 | |
| 342 | 348 | if (parent_pointer) { |
| 343 | 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 | 16 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); |
| 17 | 17 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); |
| 18 | 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 | 20 | bool is_node_void_expr(AstNode *node); |
| 21 | 21 | uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry); |
| 22 | uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry); | |
| 22 | 23 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint8_t size_in_bits); |
| 23 | 24 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint8_t size_in_bits); |
| 24 | 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 | 1379 | |
| 1380 | 1380 | static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) { |
| 1381 | 1381 | TypeTableEntry *child_type = instruction->base.value.type; |
| 1382 | if (!type_has_bits(child_type)) { | |
| 1382 | if (!type_has_bits(child_type)) | |
| 1383 | 1383 | return nullptr; |
| 1384 | } | |
| 1384 | ||
| 1385 | 1385 | LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); |
| 1386 | 1386 | TypeTableEntry *ptr_type = instruction->ptr->value.type; |
| 1387 | 1387 | assert(ptr_type->id == TypeTableEntryIdPointer); |
| 1388 | 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 | 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 | 9067 | } |
| 9068 | 9068 | } |
| 9069 | 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 | 9072 | } else { |
| 9072 | 9073 | return ir_analyze_container_member_access_inner(ira, bare_type, field_name, |
| 9073 | 9074 | field_ptr_instruction, container_ptr, container_type); |
test/cases/struct.zig+31| ... | ... | @@ -225,3 +225,34 @@ fn packedStruct() { |
| 225 | 225 | const four = foo.x + foo.y; |
| 226 | 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 | } |