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
This commit is contained in:
Andrew Kelley 2017-02-16 15:45:41 -05:00
parent 4b5cc80f66
commit fc5d47b9b9
6 changed files with 66 additions and 9 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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;
}