aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-02-16 15:45:41 -0500
committerAndrew Kelley <superjoe30@gmail.com>2017-02-16 15:45:41 -0500
commitfc5d47b9b960aa08d65bf0dfe3d6395c811f793b (patch)
tree2ccc51b0a0f2429793c4be5075bfda53b1b01b65
parent4b5cc80f665314067e0e5b96c859acca1b2e1cb0 (diff)
downloadzig-fc5d47b9b960aa08d65bf0dfe3d6395c811f793b.tar.gz
zig-fc5d47b9b960aa08d65bf0dfe3d6395c811f793b.zip
reading from a bit field partially works
See #261 Still need to do: * reading a field that has bit offset 0 but still needs to shift and truncate * writing a field
-rw-r--r--src/all_types.hpp3
-rw-r--r--src/analyze.cpp12
-rw-r--r--src/analyze.hpp3
-rw-r--r--src/codegen.cpp23
-rw-r--r--src/ir.cpp3
-rw-r--r--test/cases/struct.zig31
6 files changed, 66 insertions, 9 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 97e6076b51..d869f2d437 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -852,6 +852,7 @@ struct TypeTableEntryPointer {
TypeTableEntry *child_type;
bool is_const;
bool is_volatile;
+ uint32_t bit_offset;
};
struct TypeTableEntryInt {
@@ -1202,7 +1203,7 @@ struct TypeId {
TypeTableEntry *child_type;
bool is_const;
bool is_volatile;
- uint8_t bit_offset;
+ uint32_t bit_offset;
} pointer;
struct {
TypeTableEntry *child_type;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 88337a4959..1b248ba128 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -261,7 +261,7 @@ uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
}
// This has to do with packed structs
-static uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
+uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
TypeTableEntry *canon_type = get_underlying_type(type_entry);
if (!type_has_bits(type_entry))
@@ -287,7 +287,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
}
TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
- uint8_t bit_offset, bool is_volatile)
+ uint32_t bit_offset, bool is_volatile)
{
assert(child_type->id != TypeTableEntryIdInvalid);
@@ -316,7 +316,12 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
const char *const_str = is_const ? "const " : "";
const char *volatile_str = is_volatile ? "volatile " : "";
buf_resize(&entry->name, 0);
- buf_appendf(&entry->name, "&%s%s%s", const_str, volatile_str, buf_ptr(&child_type->name));
+ if (bit_offset == 0) {
+ buf_appendf(&entry->name, "&%s%s%s", const_str, volatile_str, buf_ptr(&child_type->name));
+ } else {
+ buf_appendf(&entry->name, "&:%" PRIu8 " %s%s%s", bit_offset, const_str,
+ volatile_str, buf_ptr(&child_type->name));
+ }
TypeTableEntry *canon_child_type = get_underlying_type(child_type);
assert(canon_child_type->id != TypeTableEntryIdInvalid);
@@ -338,6 +343,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
entry->data.pointer.child_type = child_type;
entry->data.pointer.is_const = is_const;
entry->data.pointer.is_volatile = is_volatile;
+ entry->data.pointer.bit_offset = bit_offset;
if (parent_pointer) {
*parent_pointer = entry;
diff --git a/src/analyze.hpp b/src/analyze.hpp
index 1214468940..4cdcea556f 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -16,9 +16,10 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *m
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type, bool is_const,
- uint8_t bit_offset, bool is_volatile);
+ uint32_t bit_offset, bool is_volatile);
bool is_node_void_expr(AstNode *node);
uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
+uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry);
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, uint8_t size_in_bits);
TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, uint8_t size_in_bits);
TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 8180034956..0d8ef0b03a 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -1379,14 +1379,31 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) {
TypeTableEntry *child_type = instruction->base.value.type;
- if (!type_has_bits(child_type)) {
+ if (!type_has_bits(child_type))
return nullptr;
- }
+
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
TypeTableEntry *ptr_type = instruction->ptr->value.type;
assert(ptr_type->id == TypeTableEntryIdPointer);
bool is_volatile = ptr_type->data.pointer.is_volatile;
- return get_handle_value(g, ptr, child_type, is_volatile);
+
+ uint32_t bit_offset = ptr_type->data.pointer.bit_offset;
+ if (bit_offset == 0)
+ return get_handle_value(g, ptr, child_type, is_volatile);
+
+ assert(!handle_is_ptr(child_type));
+
+ LLVMValueRef containing_int = LLVMBuildLoad(g->builder, ptr, "");
+ LLVMSetVolatile(containing_int, 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 shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
+
+ return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
}
static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
diff --git a/src/ir.cpp b/src/ir.cpp
index 03b77a69f7..ddb2164ad5 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -9067,7 +9067,8 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
}
}
ir_build_struct_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
- return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, 0, is_volatile);
+ return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const,
+ field->packed_bits_offset, is_volatile);
} else {
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
field_ptr_instruction, container_ptr, container_type);
diff --git a/test/cases/struct.zig b/test/cases/struct.zig
index fd49d00f76..403133e369 100644
--- a/test/cases/struct.zig
+++ b/test/cases/struct.zig
@@ -225,3 +225,34 @@ fn packedStruct() {
const four = foo.x + foo.y;
assert(four == 4);
}
+
+
+const u2 = @intType(false, 2);
+const u3 = @intType(false, 3);
+
+const BitField1 = packed struct {
+ a: u3,
+ b: u3,
+ c: u2,
+};
+
+fn bitFieldAccess() {
+ @setFnTest(this);
+
+ const data = BitField1 {
+ .a = 1,
+ .b = 2,
+ .c = 3,
+ };
+ assert(getB(&data) == 2);
+ assert(getC(&data) == 3);
+ comptime assert(@sizeOf(BitField1) == 1);
+}
+
+fn getB(data: &const BitField1) -> u3 {
+ return data.b;
+}
+
+fn getC(data: &const BitField1) -> u2 {
+ return data.c;
+}