mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
Bitstruct in struct fix.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user