Bitstruct in struct fix.

This commit is contained in:
Christoffer Lerno
2024-07-13 01:54:45 +02:00
parent 3f45ed14b9
commit 0e62423e06
7 changed files with 47 additions and 26 deletions

View File

@@ -15,6 +15,8 @@
- `--no-headers` option to suppress creating headers when generating a library.
- Support c-file compilation in libraries.
- Allow using $defined(&a[1]) to check if the operation is supported.
- Max number of members in a struct is limited to 65535.
- The maximum number of parameters in a call is now 255, up from 127.
### Fixes
- Error with unsigned compare in `@ensure` when early returning 0 #1207.
@@ -35,6 +37,7 @@
- Fix ABI lowering for 128 bit vectors on Linux.
- Bad error message when using a generic method without generic parameters #1228
- Private function called from nested macro not visible to linker #1232
- Bitstructs in structs would not be correctly be handled in some cases.
### Stdlib changes
- Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions.

View File

@@ -907,6 +907,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
copy_decl_type(copy);
MACRO_COPY_TYPE_LIST(copy->interfaces);
MACRO_COPY_DECL_LIST(copy->strukt.members);
MACRO_COPY_DECLID(copy->strukt.padded_decl_id);
MACRO_COPY_DECL_LIST(copy->methods);
break;
case DECL_DECLARRAY:

View File

@@ -271,8 +271,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_
LLVMTypeRef element_type_llvm = llvm_get_type(c, element_type);
AlignSize expected_align = llvm_abi_alignment(c, element_type_llvm);
ConstInitializer **elements = const_init->init_array.elements;
unsigned element_count = vec_size(elements);
assert(element_count > 0 && "Array should always have gotten at least one element.");
assert(vec_size(elements) > 0 && "Array should always have gotten at least one element.");
ArrayIndex current_index = 0;
unsigned alignment = 0;
LLVMValueRef *parts = NULL;

View File

@@ -804,14 +804,16 @@ static void llvm_emit_member_addr(GenContext *c, BEValue *value, Decl *parent, D
} while (found != member);
}
static void llvm_emit_bitstruct_member(GenContext *c, BEValue *value, Decl *parent, Decl *member)
static Decl *llvm_emit_bitstruct_member(GenContext *c, BEValue *value, Decl *parent, Decl *member)
{
assert(member->resolve_status == RESOLVE_DONE);
Decl *found = NULL;
Decl *found = parent;
Decl *last = NULL;
do
{
ArrayIndex index = find_member_index(parent, member);
assert(index > -1);
last = found;
found = parent->strukt.members[index];
switch (parent->type->canonical->type_kind)
{
@@ -829,6 +831,7 @@ static void llvm_emit_bitstruct_member(GenContext *c, BEValue *value, Decl *pare
}
parent = found;
} while (found != member);
return last ? last : parent;
}
static LLVMValueRef llvm_emit_bswap(GenContext *c, LLVMValueRef value)
@@ -838,6 +841,7 @@ static LLVMValueRef llvm_emit_bswap(GenContext *c, LLVMValueRef value)
return LLVMConstBswap(value);
}
LLVMTypeRef type = LLVMTypeOf(value);
assert(type != c->byte_type);
return llvm_emit_call_intrinsic(c, intrinsic_id.bswap, &type, 1, &value, 1);
}
@@ -871,6 +875,7 @@ static inline void llvm_extract_bool_bit_from_array(GenContext *c, BEValue *be_v
static inline LLVMValueRef llvm_bswap_non_integral(GenContext *c, LLVMValueRef value, unsigned bitsize)
{
if (bitsize <= 8) return value;
assert(is_power_of_two(bitsize));
LLVMValueRef shifted = llvm_emit_shl_fixed(c, value, (int)llvm_bitsize(c, LLVMTypeOf(value)) - (int)bitsize);
return llvm_emit_bswap(c, shifted);
}
@@ -942,9 +947,8 @@ static inline void llvm_extract_bitvalue_from_array(GenContext *c, BEValue *be_v
}
static inline void llvm_extract_bitvalue(GenContext *c, BEValue *be_value, Expr *parent, Decl *member)
static inline void llvm_extract_bitvalue(GenContext *c, BEValue *be_value, Decl *parent_decl, Decl *member)
{
Decl *parent_decl = type_flatten(parent->type)->decl;
if (be_value->type->type_kind == TYPE_ARRAY)
{
llvm_extract_bitvalue_from_array(c, be_value, member, parent_decl);
@@ -1126,14 +1130,14 @@ static inline void llvm_emit_bitassign_expr(GenContext *c, BEValue *be_value, Ex
BEValue parent;
Decl *member = lhs->access_expr.ref;
llvm_emit_expr(c, &parent, parent_expr);
llvm_emit_bitstruct_member(c, &parent, type_flatten(parent_expr->type)->decl, member);
Decl *parent_decl = llvm_emit_bitstruct_member(c, &parent, type_flatten(parent_expr->type)->decl, member);
// If we have assign + op, load the current value, perform the operation.
if (expr->binary_expr.operator != BINARYOP_ASSIGN)
{
// Grab the current value.
BEValue value = parent;
llvm_extract_bitvalue(c, &value, parent_expr, member);
llvm_extract_bitvalue(c, &value, parent_decl, member);
// Perform the operation and place it in be_value
llvm_emit_binary(c, be_value, expr, &value, binaryop_assign_base_op(expr->binary_expr.operator));
}
@@ -1152,10 +1156,10 @@ static inline void llvm_emit_bitassign_expr(GenContext *c, BEValue *be_value, Ex
// To start the assign, pull out the current value.
LLVMValueRef current_value = llvm_load_value_store(c, &parent);
bool bswap = bitstruct_requires_bitswap(parent_type->decl);
bool bswap = bitstruct_requires_bitswap(parent_decl);
if (bswap) current_value = llvm_emit_bswap(c, current_value);
LLVMValueRef value = llvm_load_value_store(c, be_value);
current_value = llvm_emit_bitstruct_value_update(c, current_value, type_size(parent.type) * 8, LLVMTypeOf(current_value), member, value);
current_value = llvm_emit_bitstruct_value_update(c, current_value, type_size(parent_decl->type) * 8, LLVMTypeOf(current_value), member, value);
if (bswap) current_value = llvm_emit_bswap(c, current_value);
llvm_store_raw(c, &parent, current_value);
}
@@ -1167,8 +1171,8 @@ static inline void llvm_emit_bitaccess(GenContext *c, BEValue *be_value, Expr *e
Decl *member = expr->access_expr.ref;
assert(be_value && be_value->type);
llvm_emit_bitstruct_member(c, be_value, type_flatten(parent->type)->decl, member);
llvm_extract_bitvalue(c, be_value, parent, expr->access_expr.ref);
Decl *parent_decl = llvm_emit_bitstruct_member(c, be_value, type_flatten(parent->type)->decl, member);
llvm_extract_bitvalue(c, be_value, parent_decl, expr->access_expr.ref);
}
static inline void llvm_emit_access_addr(GenContext *c, BEValue *be_value, Expr *expr)
@@ -2037,7 +2041,7 @@ static void llvm_emit_initialize_designated_element(GenContext *c, BEValue *ref,
llvm_emit_expr(c, &exprval, expr);
LLVMValueRef val = llvm_load_value_store(c, &exprval);
LLVMTypeRef bitstruct_type = llvm_get_type(c, underlying_type);
bool is_bitswap = bitstruct_requires_bitswap(decl);
bool is_bitswap = bitstruct_requires_bitswap(type->decl);
if (underlying_type->type_kind == TYPE_ARRAY)
{
llvm_emit_update_bitstruct_array(c, value.value, value.alignment, bitstruct_type, is_bitswap, member, val);
@@ -2150,6 +2154,7 @@ static inline void llvm_emit_initialize_reference_designated(GenContext *c, BEVa
static bool bitstruct_requires_bitswap(Decl *decl)
{
assert(decl->decl_kind == DECL_BITSTRUCT);
bool big_endian = platform_target.big_endian;
if (decl->bitstruct.big_endian) return !big_endian;
if (decl->bitstruct.little_endian) return big_endian;
@@ -2435,27 +2440,26 @@ static inline void llvm_emit_pre_post_inc_dec_bitstruct(GenContext *c, BEValue *
BEValue parent;
Decl *member = lhs->access_expr.ref;
llvm_emit_expr(c, &parent, parent_expr);
llvm_emit_bitstruct_member(c, &parent, type_flatten(parent_expr->type)->decl, member);
Decl *parent_decl = llvm_emit_bitstruct_member(c, &parent, type_flatten(parent_expr->type)->decl, member);
BEValue value = parent;
llvm_extract_bitvalue(c, &value, parent_expr, member);
llvm_extract_bitvalue(c, &value, parent_decl, member);
LLVMValueRef value_start = llvm_load_value_store(c, &value);
LLVMValueRef result = llvm_emit_add_int(c, value.type, value_start, llvm_const_int(c, value.type, diff), lhs->span);
llvm_value_set(be_value, pre ? result : value_start, value.type);
Type *parent_type = type_flatten(parent_expr->type);
if (type_lowering(parent_type)->type_kind == TYPE_ARRAY)
if (type_lowering(parent_decl->type)->type_kind == TYPE_ARRAY)
{
llvm_emit_bitassign_array(c, result, parent, parent_type->decl, member);
llvm_emit_bitassign_array(c, result, parent, parent_decl, member);
return;
}
// To start the assign, pull out the current value.
LLVMValueRef current_value = llvm_load_value_store(c, &parent);
bool bswap = bitstruct_requires_bitswap(parent_type->decl);
bool bswap = bitstruct_requires_bitswap(parent_decl);
if (bswap) current_value = llvm_emit_bswap(c, current_value);
current_value = llvm_emit_bitstruct_value_update(c, current_value, type_size(parent.type) * 8, LLVMTypeOf(current_value), member, result);
current_value = llvm_emit_bitstruct_value_update(c, current_value, type_size(parent_decl->type) * 8, LLVMTypeOf(current_value), member, result);
if (bswap) current_value = llvm_emit_bswap(c, current_value);
llvm_store_raw(c, &parent, current_value);
}

View File

@@ -276,7 +276,8 @@ static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent
static inline bool sema_check_struct_holes(SemaContext *context, Decl *decl, Decl *member, Type *member_type)
{
member_type = type_flatten(member_type);
if (member_type->type_kind != TYPE_STRUCT && member_type->type_kind != TYPE_UNION) return true;
if (!type_is_union_or_strukt(member_type)) return true;
assert(decl_is_struct_type(member_type->decl));
if (!member_type->decl->strukt.padded_decl_id) return true;
if (!decl->strukt.padded_decl_id) decl->strukt.padded_decl_id = member_type->decl->strukt.padded_decl_id;
if (decl->attr_compact)
@@ -377,6 +378,7 @@ static bool sema_analyse_union_members(SemaContext *context, Decl *decl)
decl->is_packed = decl->is_packed && max_alignment > 1;
// "Representative" type is the one with the maximum alignment.
assert(max_alignment_element >= 0);
decl->strukt.union_rep = max_alignment_element;
// All members share the same alignment
@@ -590,6 +592,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl)
if (align_offset - offset != 0)
{
assert(decl_is_struct_type(decl));
if (!decl->strukt.padded_decl_id) decl->strukt.padded_decl_id = declid(member);
if (decl->attr_nopadding || member->attr_nopadding)
{
@@ -647,6 +650,7 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl)
if (size != offset)
{
assert(decl_is_struct_type(decl));
if (!decl->strukt.padded_decl_id) decl->strukt.padded_decl_id = declid(decl);
if (decl->attr_nopadding)
{

View File

@@ -1013,7 +1013,7 @@ static inline bool array_structurally_equivalent_to_struct(Type *array, Type *ty
Decl **members = type->decl->strukt.members;
// For structs / errors, all members must match.
ArrayIndex offset = 0;
ArrayIndex offset = 0;
AlignSize align_size = type_abi_alignment(array);
Type *array_base = array->array.base;
FOREACH(Decl *, member, members)

View File

@@ -7,11 +7,16 @@ fn int test1(
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 100
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded the max of 127. To accept more arguments, consider using varargs
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 120
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int // 200
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 200
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 220
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 240
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int // 300
) { return 1; }
fn int test2(
@@ -20,11 +25,16 @@ fn int test2(
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 100
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 120
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded the max of 127.
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 200
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 220
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 240
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // #error: The number of params exceeded
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, //
int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, // 300
int... x
) { return 1; }