authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-16 18:42:52-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-16 18:42:52-05:00
log244362fed7ed9280a0612c7c57ed67f6fa33b40d
tree5d204f4e7aea69e2d5986015edb236c69a6dc582
parentb6e7a0dadd86ce401e82ec53d6874e9934826c2d

ability to write to bit fields

See #261

2 files changed, 47 insertions(+), 10 deletions(-)

src/codegen.cpp+33-5
...@@ -1410,17 +1410,45 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir...@@ -1410,17 +1410,45 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir
1410 TypeTableEntry *ptr_type = get_underlying_type(instruction->ptr->value.type);1410 TypeTableEntry *ptr_type = get_underlying_type(instruction->ptr->value.type);
1411 TypeTableEntry *child_type = get_underlying_type(ptr_type->data.pointer.child_type);1411 TypeTableEntry *child_type = get_underlying_type(ptr_type->data.pointer.child_type);
14121412
1413 if (!type_has_bits(child_type)) {1413 if (!type_has_bits(child_type))
1414 return nullptr;1414 return nullptr;
1415 }1415
1416 if (handle_is_ptr(child_type)) {1416 if (handle_is_ptr(child_type))
1417 return gen_struct_memcpy(g, value, ptr, child_type);1417 return gen_struct_memcpy(g, value, ptr, child_type);
1418
1419 uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
1420 if (bit_offset == 0) {
1421 LLVMTypeRef ptr_child_ref = LLVMGetElementType(LLVMTypeOf(ptr));
1422 bool need_to_do_some_bit_stuff =
1423 LLVMGetTypeKind(ptr_child_ref) == LLVMIntegerTypeKind &&
1424 LLVMGetTypeKind(child_type->type_ref) == LLVMIntegerTypeKind &&
1425 LLVMGetIntTypeWidth(child_type->type_ref) < LLVMGetIntTypeWidth(ptr_child_ref);
1426 if (!need_to_do_some_bit_stuff) {
1427 LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, value, ptr);
1428 LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);
1429 return nullptr;
1430 }
1418 }1431 }
14191432
1420 LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, value, ptr);1433 LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, "");
14211434
1422 LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);1435 uint32_t child_bit_count = type_size_bits(g, child_type);
1436 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
1437 uint32_t shift_amt = host_bit_count - bit_offset - child_bit_count;
1438 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
1439
1440 LLVMValueRef mask_val = LLVMConstAllOnes(child_type->type_ref);
1441 mask_val = LLVMConstZExt(mask_val, LLVMTypeOf(containing_int));
1442 mask_val = LLVMConstShl(mask_val, shift_amt_val);
1443 mask_val = LLVMConstNot(mask_val);
14231444
1445 LLVMValueRef anded_containing_int = LLVMBuildAnd(g->builder, containing_int, mask_val, "");
1446 LLVMValueRef extended_value = LLVMBuildZExt(g->builder, value, LLVMTypeOf(containing_int), "");
1447 LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, "");
1448 LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, "");
1449
1450 LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, ored_value, ptr);
1451 LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile);
1424 return nullptr;1452 return nullptr;
1425}1453}
14261454
test/cases/struct.zig+14-5
...@@ -236,18 +236,27 @@ const BitField1 = packed struct {...@@ -236,18 +236,27 @@ const BitField1 = packed struct {
236 c: u2,236 c: u2,
237};237};
238238
239const bit_field_1 = BitField1 {
240 .a = 1,
241 .b = 2,
242 .c = 3,
243};
244
239fn bitFieldAccess() {245fn bitFieldAccess() {
240 @setFnTest(this);246 @setFnTest(this);
241247
242 const data = BitField1 {248 var data = bit_field_1;
243 .a = 1,
244 .b = 2,
245 .c = 3,
246 };
247 assert(getA(&data) == 1);249 assert(getA(&data) == 1);
248 assert(getB(&data) == 2);250 assert(getB(&data) == 2);
249 assert(getC(&data) == 3);251 assert(getC(&data) == 3);
250 comptime assert(@sizeOf(BitField1) == 1);252 comptime assert(@sizeOf(BitField1) == 1);
253
254 data.b += 1;
255 assert(data.b == 3);
256
257 data.a += 1;
258 assert(data.a == 2);
259 assert(data.b == 3);
251}260}
252261
253fn getA(data: &const BitField1) -> u3 {262fn getA(data: &const BitField1) -> u3 {