aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-02-16 18:42:52 -0500
committerAndrew Kelley <superjoe30@gmail.com>2017-02-16 18:42:52 -0500
commit244362fed7ed9280a0612c7c57ed67f6fa33b40d (patch)
tree5d204f4e7aea69e2d5986015edb236c69a6dc582 /src/codegen.cpp
parentb6e7a0dadd86ce401e82ec53d6874e9934826c2d (diff)
downloadzig-244362fed7ed9280a0612c7c57ed67f6fa33b40d.tar.gz
zig-244362fed7ed9280a0612c7c57ed67f6fa33b40d.zip
ability to write to bit fields
See #261
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp38
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;
}