diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-02-16 18:42:52 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-02-16 18:42:52 -0500 |
| commit | 244362fed7ed9280a0612c7c57ed67f6fa33b40d (patch) | |
| tree | 5d204f4e7aea69e2d5986015edb236c69a6dc582 /src | |
| parent | b6e7a0dadd86ce401e82ec53d6874e9934826c2d (diff) | |
| download | zig-244362fed7ed9280a0612c7c57ed67f6fa33b40d.tar.gz zig-244362fed7ed9280a0612c7c57ed67f6fa33b40d.zip | |
ability to write to bit fields
See #261
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen.cpp | 38 |
1 files changed, 33 insertions, 5 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp index 3d5f675787..69cfa66f04 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1410,17 +1410,45 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir TypeTableEntry *ptr_type = get_underlying_type(instruction->ptr->value.type); TypeTableEntry *child_type = get_underlying_type(ptr_type->data.pointer.child_type); - if (!type_has_bits(child_type)) { + if (!type_has_bits(child_type)) return nullptr; - } - if (handle_is_ptr(child_type)) { + + if (handle_is_ptr(child_type)) return gen_struct_memcpy(g, value, ptr, child_type); + + uint32_t bit_offset = ptr_type->data.pointer.bit_offset; + if (bit_offset == 0) { + LLVMTypeRef ptr_child_ref = LLVMGetElementType(LLVMTypeOf(ptr)); + bool need_to_do_some_bit_stuff = + LLVMGetTypeKind(ptr_child_ref) == LLVMIntegerTypeKind && + LLVMGetTypeKind(child_type->type_ref) == LLVMIntegerTypeKind && + LLVMGetIntTypeWidth(child_type->type_ref) < LLVMGetIntTypeWidth(ptr_child_ref); + if (!need_to_do_some_bit_stuff) { + LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, value, ptr); + LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile); + return nullptr; + } } - LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, value, ptr); + LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, ""); - LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.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 mask_val = LLVMConstAllOnes(child_type->type_ref); + mask_val = LLVMConstZExt(mask_val, LLVMTypeOf(containing_int)); + mask_val = LLVMConstShl(mask_val, shift_amt_val); + mask_val = LLVMConstNot(mask_val); + LLVMValueRef anded_containing_int = LLVMBuildAnd(g->builder, containing_int, mask_val, ""); + LLVMValueRef extended_value = LLVMBuildZExt(g->builder, value, LLVMTypeOf(containing_int), ""); + LLVMValueRef shifted_value = LLVMBuildShl(g->builder, extended_value, shift_amt_val, ""); + LLVMValueRef ored_value = LLVMBuildOr(g->builder, shifted_value, anded_containing_int, ""); + + LLVMValueRef llvm_instruction = LLVMBuildStore(g->builder, ored_value, ptr); + LLVMSetVolatile(llvm_instruction, ptr_type->data.pointer.is_volatile); return nullptr; } |
