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:
parent
4b5cc80f66
commit
fc5d47b9b9
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user