From 4e47f0b6241b1d1d18f558fd09d345414203e643 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 7 Nov 2021 21:29:18 +0100 Subject: [PATCH] Fixes to bitstruct and work on correct behaviour when embedded in structs. --- src/compiler/enums.h | 2 + src/compiler/llvm_codegen_expr.c | 37 ++++---- src/compiler/sema_casts.c | 28 +++++- src/compiler/sema_expr.c | 89 +++++++++++++++---- test/test_suite/bitstruct/bitfield_access.c3t | 22 ++--- .../bitstruct/bitstruct_access_signed.c3t | 12 +-- .../test_suite/bitstruct/bitstruct_arrays.c3t | 24 ++--- test/test_suite/bitstruct/bitstruct_init.c3 | 63 +++++++++++++ .../bitstruct/bitstruct_intcontainer.c3t | 38 ++++---- 9 files changed, 233 insertions(+), 82 deletions(-) create mode 100644 test/test_suite/bitstruct/bitstruct_init.c3 diff --git a/src/compiler/enums.h b/src/compiler/enums.h index b83165823..b68f0717f 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -82,6 +82,8 @@ typedef enum typedef enum { + CAST_BSARRY, + CAST_BSINT, CAST_ERROR, CAST_ERBOOL, CAST_EUBOOL, diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 1c8bef3e7..3320e90de 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -166,10 +166,11 @@ LLVMValueRef llvm_const_high_bitmask(LLVMTypeRef type, int type_bits, int high_b return LLVMConstNot(LLVMConstLShr(LLVMConstAllOnes(type), LLVMConstInt(type, high_bits, 0))); } -LLVMValueRef llvm_mask_low_bits(GenContext *c, LLVMValueRef value, int type_bits, int low_bits) +LLVMValueRef llvm_mask_low_bits(GenContext *c, LLVMValueRef value, int low_bits) { LLVMTypeRef type = LLVMTypeOf(value); if (low_bits < 1) return LLVMConstNull(type); + int type_bits = llvm_bitsize(c, type); if (type_bits <= low_bits) return value; LLVMValueRef mask = LLVMConstLShr(LLVMConstAllOnes(type), LLVMConstInt(type, type_bits - low_bits, 0)); if (LLVMIsConstant(value)) @@ -703,7 +704,7 @@ static inline void llvm_extract_bitvalue_from_array(GenContext *c, BEValue *be_v } else { - res = llvm_mask_low_bits(c, res, bitsize, end - start + 1); + res = llvm_mask_low_bits(c, res, end - start + 1); } llvm_value_set(be_value, res, member_type); } @@ -759,19 +760,8 @@ static inline void llvm_extract_bitvalue(GenContext *c, BEValue *be_value, Expr value = LLVMBuildLShr(c->builder, value, LLVMConstInt(container_type, start, 0), ""); } int bits_needed = end - start + 1; - if (bits_needed < container_bit_size && bits_needed > 1) - { - LLVMValueRef mask = LLVMConstLShr(LLVMConstAllOnes(container_type), LLVMConstInt(container_type, container_bit_size - bits_needed - 1, 0)); - value = LLVMBuildAnd(c->builder, value, mask, ""); - } - if (member_type_size < container_bit_size) - { - value = LLVMBuildTrunc(c->builder, value, llvm_get_type(c, member_type), ""); - } - else if (member_type_size > container_bit_size) - { - value = LLVMBuildZExt(c->builder, value, llvm_get_type(c, member_type), ""); - } + value = llvm_mask_low_bits(c, value, bits_needed); + value = llvm_zext_trunc(c, value, llvm_get_type(c, member_type)); } llvm_value_set(be_value, value, member_type); } @@ -932,7 +922,6 @@ static inline void llvm_emit_bitassign_expr(GenContext *c, BEValue *be_value, Ex // Now we might need to truncate or widen the value to insert: LLVMValueRef value = llvm_value_rvalue_store(c, be_value); - int value_bitsize = type_size(be_value->type) * 8; value = llvm_zext_trunc(c, value, struct_type); // Shift to the correct location. value = llvm_emit_shl(c, value, start_bit); @@ -1007,6 +996,18 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_ switch (cast_kind) { + case CAST_BSARRY: + llvm_value_addr(c, value); + value->value = llvm_emit_bitcast(c, value->value, type_get_ptr(to_type)); + value->type = to_type; + llvm_value_rvalue(c, value); + return; + case CAST_BSINT: + llvm_value_addr(c, value); + value->value = llvm_emit_bitcast(c, value->value, type_get_ptr(to_type)); + value->type = to_type; + llvm_value_rvalue(c, value); + return; case CAST_EUINT: case CAST_ERINT: to_type = type_lowering(to_type); @@ -1624,7 +1625,7 @@ LLVMValueRef llvm_emit_const_bitstruct_array(GenContext *c, ConstInitializer *in int start_byte = start_bit / 8; int end_byte = end_bit / 8; ByteSize member_type_bitsize = type_size(member_type) * 8; - value = llvm_mask_low_bits(c, value, member_type_bitsize, bit_size); + value = llvm_mask_low_bits(c, value, bit_size); if (big_endian && bit_size > 8) { value = llvm_bswap_non_integral(c, value, bit_size); @@ -1643,7 +1644,7 @@ LLVMValueRef llvm_emit_const_bitstruct_array(GenContext *c, ConstInitializer *in } if (j == end_byte) { - to_or = llvm_mask_low_bits(c, to_or, member_type_bitsize, end_bit % 8 + 1); + to_or = llvm_mask_low_bits(c, to_or, end_bit % 8 + 1); } if (member_type_bitsize > 8) to_or = LLVMConstTrunc(to_or, c->byte_type); LLVMValueRef current_value = llvm_emit_extract_value(c, data, j); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 8dbf6d333..39ffa5ac0 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -11,6 +11,8 @@ #define FLOAT64_LIMIT 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0000000000000000 #define FLOAT16_LIMIT 65504 +static bool bitstruct_cast(Expr *expr, Type *from_type, Type *to, Type *to_type); + static inline bool insert_cast(Expr *expr, CastKind kind, Type *type) { assert(expr->resolve_status == RESOLVE_DONE); @@ -1260,7 +1262,7 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type, boo case CT_TYPES: UNREACHABLE case TYPE_BITSTRUCT: - UNREACHABLE + return bitstruct_cast(expr, from_type, to, to_type); case TYPE_FAILABLE: TODO case TYPE_BOOL: @@ -1336,6 +1338,30 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type, boo } UNREACHABLE } + +static bool bitstruct_cast(Expr *expr, Type *from_type, Type *to, Type *to_type) +{ + Type *base_type = type_flatten_distinct(from_type->decl->bitstruct.base_type->type); + assert(type_size(to) == type_size(base_type)); + if (type_is_integer(base_type) && type_is_integer(to)) + { + expr->type = to_type; + return true; + } + if (base_type->type_kind == TYPE_ARRAY && to->type_kind == TYPE_ARRAY) + { + expr->type = to_type; + return true; + } + if (type_is_integer(base_type)) + { + assert(to->type_kind == TYPE_ARRAY); + return insert_cast(expr, CAST_BSARRY, to_type); + } + assert(base_type->type_kind == TYPE_ARRAY); + return insert_cast(expr, CAST_BSINT, to_type); +} + bool cast(Expr *expr, Type *to_type) { assert(!type_is_failable(to_type)); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index e96a98bbe..a0d06e1bb 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -152,6 +152,8 @@ bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) { case CAST_VFTOERR: case CAST_ERROR: + case CAST_BSINT: + case CAST_BSARRY: return false; case CAST_ERBOOL: case CAST_EUBOOL: @@ -235,6 +237,38 @@ static inline bool expr_list_is_constant_eval(Expr **exprs, ConstantEvalKind eva return true; } +static bool sema_bit_assignment_check(Expr *right, Decl *member) +{ + if (right->expr_kind != EXPR_CONST || !type_is_integer(right->type)) return true; + + int bits = member->var.end_bit - member->var.start_bit + 1; + + if (bits >= type_size(right->type) * 8 || int_is_zero(right->const_expr.ixx)) return true; + + // Check that we're not assigning consts that will be cut. + + TypeKind kind = right->const_expr.ixx.type; + Int128 i = right->const_expr.ixx.i; + int bits_used; + if (type_kind_is_signed(kind)) + { + if (i128_is_neg(i)) + { + i = i128_neg(i); + i = i128_sub64(i, 1); + } + bits_used = 1 + 128 - i128_clz(&i); + } + else + { + bits_used = 128 - i128_clz(&i); + } + if (bits_used <= bits) return true; + + SEMA_ERROR(right, + "This constant would be truncated if stored in the bitstruct, do you need a wider bit range?"); + return false; +} bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) { RETRY: @@ -1414,16 +1448,14 @@ static inline bool sema_expr_analyse_func_invocation(Context *context, FunctionS return true; } -static inline bool sema_expr_analyse_var_call(Context *context, Expr *expr, Decl *var_decl, bool failable) +static inline bool sema_expr_analyse_var_call(Context *context, Expr *expr, Type *func_ptr_type, bool failable) { - Type *func_ptr_type = var_decl->type->canonical; if (func_ptr_type->type_kind != TYPE_POINTER || func_ptr_type->pointer->type_kind != TYPE_FUNC) { - SEMA_ERROR(expr, "Only macros, functions and function pointers maybe invoked, this is of type '%s'.", type_to_error_string(var_decl->type)); + SEMA_ERROR(expr, "Only macros, functions and function pointers maybe invoked, this is of type '%s'.", type_to_error_string(func_ptr_type)); return false; } expr->call_expr.is_pointer_call = true; - failable |= IS_FAILABLE(var_decl); return sema_expr_analyse_func_invocation(context, func_ptr_type->pointer->func.signature, expr, @@ -1891,6 +1923,10 @@ bool sema_expr_analyse_general_call(Context *context, Expr *expr, Decl *decl, Ex } } expr->call_expr.is_type_method = struct_var != NULL; + if (decl == NULL) + { + return sema_expr_analyse_var_call(context, expr, type_flatten_distinct_failable(expr->call_expr.function->type), failable); + } switch (decl->decl_kind) { case DECL_MACRO: @@ -1908,7 +1944,7 @@ bool sema_expr_analyse_general_call(Context *context, Expr *expr, Decl *decl, Ex return false; } assert(struct_var == NULL); - return sema_expr_analyse_var_call(context, expr, decl, failable); + return sema_expr_analyse_var_call(context, expr, decl->type->canonical, failable || IS_FAILABLE(decl)); case DECL_FUNC: if (is_macro) { @@ -1978,10 +2014,19 @@ static inline bool sema_expr_analyse_call(Context *context, Expr *expr) } return false; default: + { + Type *type = type_flatten_distinct(func_expr->type); + if (type->type_kind == TYPE_POINTER && type->pointer->type_kind == TYPE_FUNC) + { + decl = NULL; + break; + } SEMA_ERROR(expr, "This value cannot be invoked, did you accidentally add ()?"); return false; + + } } - decl = decl_flatten(decl); + decl = decl ? decl_flatten(decl) : NULL; return sema_expr_analyse_general_call(context, expr, decl, struct_var, macro, failable); } @@ -2739,7 +2784,7 @@ static Decl *sema_resolve_element_for_name(Decl** decls, DesignatorElement **ele } if (!decl->name) { - assert(type_is_structlike(decl->type)); + assert(type_is_structlike(decl->type) || decl->decl_kind == DECL_BITSTRUCT); // Anonymous struct Decl *found = sema_resolve_element_for_name(decl->strukt.members, elements, index); // No match, continue... @@ -2800,25 +2845,25 @@ static int64_t sema_analyse_designator_index(Context *context, Expr *index) static Type *sema_find_type_of_element(Context *context, Type *type, DesignatorElement **elements, unsigned *curr_index, bool *is_constant, bool *did_report_error, ArrayIndex *max_index) { - Type *type_lowered = type_lowering(type); + Type *type_flattened = type_flatten(type); DesignatorElement *element = elements[*curr_index]; if (element->kind == DESIGNATOR_ARRAY || element->kind == DESIGNATOR_RANGE) { ByteSize len; Type *base; - switch (type_lowered->type_kind) + switch (type_flattened->type_kind) { case TYPE_INFERRED_ARRAY: len = MAX_ARRAYINDEX; - base = type_lowered->array.base; + base = type_flattened->array.base; break; case TYPE_ARRAY: - len = type_lowered->array.len; - base = type_lowered->array.base; + len = type_flattened->array.len; + base = type_flattened->array.base; break; case TYPE_VECTOR: - len = type_lowered->vector.len; - base = type_lowered->vector.base; + len = type_flattened->vector.len; + base = type_flattened->vector.base; break; default: return NULL; @@ -2864,11 +2909,11 @@ static Type *sema_find_type_of_element(Context *context, Type *type, DesignatorE return base; } assert(element->kind == DESIGNATOR_FIELD); - if (!type_is_structlike(type_lowered)) + if (!type_is_structlike(type_flattened) && type_flattened->type_kind != TYPE_BITSTRUCT) { return NULL; } - Decl *member = sema_resolve_element_for_name(type_lowered->decl->strukt.members, elements, curr_index); + Decl *member = sema_resolve_element_for_name(type_flattened->decl->strukt.members, elements, curr_index); if (!member) return NULL; return member->type; } @@ -3150,6 +3195,7 @@ static inline void sema_update_const_initializer_with_designator( switch (const_init->type->type_kind) { case TYPE_STRUCT: + case TYPE_BITSTRUCT: sema_update_const_initializer_with_designator_struct(const_init, curr, end, value); return; case TYPE_UNION: @@ -3247,6 +3293,15 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, bool failable = false; + bool is_bitstruct = assigned->decl_kind == DECL_BITSTRUCT; + if (is_bitstruct && assigned->bitstruct.overlap) + { + if (vec_size(assigned->strukt.members) > 1 && vec_size(elements) > 1) + { + SEMA_ERROR(elements[0], "Bitstructs with @overlap must use designated initialization."); + return false; + } + } // 3. Loop through all elements. VECEACH(elements, i) { @@ -3261,6 +3316,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(Context *context, } // 5. We know the required type, so resolve the expression. if (!sema_analyse_expr_rhs(context, members[i]->type, element, true)) return false; + if (is_bitstruct && !sema_bit_assignment_check(element, members[i])) return false; failable = failable || IS_FAILABLE(element); } assert(initializer->type); @@ -3712,6 +3768,7 @@ static bool sema_expr_analyse_assign(Context *context, Expr *expr, Expr *left, E } if (left->expr_kind == EXPR_BITACCESS) { + if (!sema_bit_assignment_check(right, left->access_expr.ref)) return false; expr->expr_kind = EXPR_BITASSIGN; } return true; diff --git a/test/test_suite/bitstruct/bitfield_access.c3t b/test/test_suite/bitstruct/bitfield_access.c3t index 97bc9e1c9..27e0544b5 100644 --- a/test/test_suite/bitstruct/bitfield_access.c3t +++ b/test/test_suite/bitstruct/bitfield_access.c3t @@ -57,13 +57,13 @@ bitstruct BitFieldCross : char[5] uint a : 5..22; } -BitField c = { 2, 4, 5 }; +BitField c = { 2, -1, 1 }; extern fn void printf(char*, ...); fn void main() { - BitField b = { 5, -3, 1 }; + BitField b = { 3, -1, 1 }; BitFieldI c1 = { 5, 0, 0 }; BitFieldI c2 = { 0, 3, 0 }; BitFieldI c3 = { 0, 0, 9 }; @@ -73,8 +73,8 @@ fn void main() BitFieldI c7 = { 0, 0, 5 }; BitField3 e1 = { 3, 1, 3, 4 }; - BitField3 e2 = { 4, 1, 3, 4 }; - BitField3 e3 = { 5, 1, 3, 4 }; + BitField3 e2 = { 1, 1, 3, 4 }; + BitField3 e3 = { 2, 1, 3, 4 }; BitField d = { }; printf("%d\n", e1.a); @@ -83,11 +83,11 @@ fn void main() BitField3u z1 = { 3, 1, 3, 4 }; BitField3u z2 = { 4, 1, 3, 4 }; - BitField3u z3 = { 9, 1, 3, 4 }; + BitField3u z3 = { 7, 1, 3, 4 }; printf("%u\n", z1.a); printf("%u\n", z2.a); printf("%u\n", z3.a); - BitFieldCross xx = { 0x12345678 }; + BitFieldCross xx = { 0x1238 }; printf("%x\n", xx.a); } @@ -111,7 +111,7 @@ entry: %z2 = alloca [3 x i8], align 1 %z3 = alloca [3 x i8], align 1 %xx = alloca [5 x i8], align 1 - store i8 85, i8* %b, align 1 + store i8 115, i8* %b, align 1 store i16 5, i16* %c1, align 2 store i16 96, i16* %c2, align 2 store i16 18432, i16* %c3, align 2 @@ -120,8 +120,8 @@ entry: store i16 5, i16* %c6, align 2 store i16 10240, i16* %c7, align 2 store [3 x i8] c"\0B\06 ", [3 x i8]* %e1, align 1 - store [3 x i8] c"\0C\06 ", [3 x i8]* %e2, align 1 - store [3 x i8] c"\0D\06 ", [3 x i8]* %e3, align 1 + store [3 x i8] c"\09\06 ", [3 x i8]* %e2, align 1 + store [3 x i8] c"\0A\06 ", [3 x i8]* %e3, align 1 store i8 0, i8* %d, align 1 %0 = getelementptr inbounds [3 x i8], [3 x i8]* %e1, i64 0, i64 0 %1 = load i8, i8* %0, align 1 @@ -143,7 +143,7 @@ entry: call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i32 0, i32 0), i32 %14) store [3 x i8] c"\0B\06 ", [3 x i8]* %z1, align 1 store [3 x i8] c"\0C\06 ", [3 x i8]* %z2, align 1 - store [3 x i8] c"\09\06 ", [3 x i8]* %z3, align 1 + store [3 x i8] c"\0F\06 ", [3 x i8]* %z3, align 1 %15 = getelementptr inbounds [3 x i8], [3 x i8]* %z1, i64 0, i64 0 %16 = load i8, i8* %15, align 1 %17 = zext i8 %16 to i32 @@ -159,7 +159,7 @@ entry: %25 = zext i8 %24 to i32 %26 = and i32 7, %25 call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.5, i32 0, i32 0), i32 %26) - store [5 x i8] c"\00\CF\0A\00\00", [5 x i8]* %xx, align 1 + store [5 x i8] c"\00G\02\00\00", [5 x i8]* %xx, align 1 %27 = getelementptr inbounds [5 x i8], [5 x i8]* %xx, i64 0, i64 0 %28 = load i8, i8* %27, align 1 %29 = zext i8 %28 to i32 diff --git a/test/test_suite/bitstruct/bitstruct_access_signed.c3t b/test/test_suite/bitstruct/bitstruct_access_signed.c3t index 4cce549c4..ae8a0bafe 100644 --- a/test/test_suite/bitstruct/bitstruct_access_signed.c3t +++ b/test/test_suite/bitstruct/bitstruct_access_signed.c3t @@ -19,11 +19,11 @@ extern fn void printf(char*, ...); fn void main() { - BitFieldCross xx = { 0, -177, 0 }; + BitFieldCross xx = { 0, -17, 0 }; printf("%d\n", xx.a); - xx = { 0xff, -177, 0xff }; + xx = { 0x1f, -17, 1 }; printf("%d\n", xx.a); - BitFieldCrossU xxu = { 0xff, 0x12345678, 0xff }; + BitFieldCrossU xxu = { 0x1f, 0x15678, 1 }; printf("%x\n", xxu.a); } @@ -34,7 +34,7 @@ define void @main() #0 { entry: %xx = alloca [3 x i8], align 1 %xxu = alloca [3 x i8], align 1 - store [3 x i8] c"\E0\E9\7F", [3 x i8]* %xx, align 1 + store [3 x i8] c"\E0\FD\7F", [3 x i8]* %xx, align 1 %0 = getelementptr inbounds [3 x i8], [3 x i8]* %xx, i64 0, i64 0 %1 = load i8, i8* %0, align 1 %2 = zext i8 %1 to i32 @@ -52,7 +52,7 @@ entry: %14 = shl i32 %13, 14 %15 = ashr i32 %14, 14 call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %15) - store [3 x i8] c"\FF\E9\FF", [3 x i8]* %xx, align 1 + store [3 x i8] c"\FF\FD\FF", [3 x i8]* %xx, align 1 %16 = load [3 x i8], [3 x i8]* %xx, align 1 %17 = getelementptr inbounds [3 x i8], [3 x i8]* %xx, i64 0, i64 0 %18 = load i8, i8* %17, align 1 @@ -71,7 +71,7 @@ entry: %31 = shl i32 %30, 14 %32 = ashr i32 %31, 14 call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i32 %32) - store [3 x i8] c"\1F\CF\8A", [3 x i8]* %xxu, align 1 + store [3 x i8] c"\1F\CF\AA", [3 x i8]* %xxu, align 1 %33 = getelementptr inbounds [3 x i8], [3 x i8]* %xxu, i64 0, i64 0 %34 = load i8, i8* %33, align 1 %35 = zext i8 %34 to i32 diff --git a/test/test_suite/bitstruct/bitstruct_arrays.c3t b/test/test_suite/bitstruct/bitstruct_arrays.c3t index 3a8860c91..01a7b2753 100644 --- a/test/test_suite/bitstruct/bitstruct_arrays.c3t +++ b/test/test_suite/bitstruct/bitstruct_arrays.c3t @@ -323,18 +323,20 @@ entry: store i64 %158, i64* %xx, align 8 %159 = load i64, i64* %xx, align 8 %160 = lshr i64 %159, 20 - %161 = trunc i64 %160 to i8 - %162 = trunc i8 %161 to i1 - %boolsi = zext i1 %162 to i32 + %161 = and i64 1, %160 + %162 = trunc i64 %161 to i8 + %163 = trunc i8 %162 to i1 + %boolsi = zext i1 %163 to i32 call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.9, i32 0, i32 0), i32 %boolsi) - %163 = load i64, i64* %xx, align 8 - %164 = and i64 %163, -1048577 - store i64 %164, i64* %xx, align 8 - %165 = load i64, i64* %xx, align 8 - %166 = lshr i64 %165, 20 - %167 = trunc i64 %166 to i8 - %168 = trunc i8 %167 to i1 - %boolsi1 = zext i1 %168 to i32 + %164 = load i64, i64* %xx, align 8 + %165 = and i64 %164, -1048577 + store i64 %165, i64* %xx, align 8 + %166 = load i64, i64* %xx, align 8 + %167 = lshr i64 %166, 20 + %168 = and i64 1, %167 + %169 = trunc i64 %168 to i8 + %170 = trunc i8 %169 to i1 + %boolsi1 = zext i1 %170 to i32 call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.10, i32 0, i32 0), i32 %boolsi1) ret void } diff --git a/test/test_suite/bitstruct/bitstruct_init.c3 b/test/test_suite/bitstruct/bitstruct_init.c3 new file mode 100644 index 000000000..e8d0e09eb --- /dev/null +++ b/test/test_suite/bitstruct/bitstruct_init.c3 @@ -0,0 +1,63 @@ +// #target +module foo; + +bitstruct Foo : uint +{ + int x : 1..3; + uint y : 11..13; + int z : 15..15; +} + +struct Bar +{ + int x; + bitstruct baz : int + { + int x : 1..3; + } +} + +struct Bar2 +{ + int x; + bitstruct : int + { + int z : 1..3; + } + +} +fn void testNested() +{ + Bar b1 = { 3, { 3 } }; + Bar b2 = { .x = 3, .baz.x = 3 }; + Bar2 b3 = { 1, 3 }; + Bar2 b4 = { .x = 123, .z = 3 }; + Bar2 b5 = { .x = 123, .z = 4 }; // #error: would be truncated + Bar2 b6 = { 1, 3 }; // #error: would be truncated + Bar b7 = { 3, { 4 } }; // #error: would be truncated + Bar b8 = { .x = 3, .baz.x = 4 }; // #error: would be truncated + +} + +fn void test() +{ + Foo abc = {}; + abc.x = -4; + abc.z = 0; + abc.z = -1; + abc.x = 3; + abc.y = 7; + abc.x = -5; // #error: would be truncated + abc.x = 4; // #error: would be truncated + abc.y = 8; // #error: would be truncated +} + +fn void test2() +{ + Foo abc = { -4, 8, 0 }; // #error: would be truncated +} + +fn void test3() +{ + Foo abc = { .x = -4, .z = 0, .y = 8 }; // #error: would be truncated +} \ No newline at end of file diff --git a/test/test_suite/bitstruct/bitstruct_intcontainer.c3t b/test/test_suite/bitstruct/bitstruct_intcontainer.c3t index ab72916f8..99eacab4a 100644 --- a/test/test_suite/bitstruct/bitstruct_intcontainer.c3t +++ b/test/test_suite/bitstruct/bitstruct_intcontainer.c3t @@ -35,72 +35,72 @@ extern fn void printf(char*, ...); fn void main() { - BitFieldCross xx = { 0, -177, 0 }; + BitFieldCross xx = { 0, -15, 0 }; printf("%d\n", xx.a); - xx = { 0xff, -177, 0xff }; + xx = { 0x1f, -15, 0x7f }; printf("%d\n", xx.a); - BitFieldCrossU xxu = { 0xff, 0x12345678, 0xffffffff }; + BitFieldCrossU xxu = { 0x1f, 0x25678, 0x1ff }; printf("%x\n", xxu.a); - BitFieldCrossUL xxy = { 0xff, 0x12345678, 0xefff_fffe, 0xfdca9597 }; + BitFieldCrossUL xxy = { 0x1f, 0x25678, 0xeffe, 0xa9597 }; printf("%x, %x, %x\n", xxy.a, xxy.c, xxy.e); - BitFieldCrossULBE xxybe = { 0xff, 0x12345678, 0xefff_fffe, 0xfdca9597 }; + BitFieldCrossULBE xxybe = { 0x1f, 0x25678, 0xeffe, 0xa9597 }; printf("%x, %x, %x\n", xxybe.a, xxybe.c, xxybe.e); } + /* #expect: foo.ll -define void @main() #0 { entry: %xx = alloca i32, align 4 %xxu = alloca i32, align 4 %xxy = alloca i64, align 8 %xxybe = alloca i64, align 8 - store i32 8382944, i32* %xx, align 4 + store i32 8388128, i32* %xx, align 4 %0 = load i32, i32* %xx, align 4 %1 = shl i32 %0, 9 %2 = ashr i32 %1, 14 call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %2) - store i32 2147478015, i32* %xx, align 4 + store i32 1073741375, i32* %xx, align 4 %3 = load i32, i32* %xx, align 4 %4 = load i32, i32* %xx, align 4 %5 = shl i32 %4, 9 %6 = ashr i32 %5, 14 call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i32 %6) - store i32 -7680225, i32* %xxu, align 4 + store i32 -3485921, i32* %xxu, align 4 %7 = load i32, i32* %xxu, align 4 %8 = lshr i32 %7, 5 - %9 = and i32 %8, 524287 + %9 = and i32 262143, %8 call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i32 0, i32 0), i32 %9) - store i64 1525365675337109279, i64* %xxy, align 8 + store i64 1525363991714123551, i64* %xxy, align 8 %10 = load i64, i64* %xxy, align 8 %11 = lshr i64 %10, 5 - %12 = and i64 %11, 524287 + %12 = and i64 262143, %11 %13 = trunc i64 %12 to i32 %14 = load i64, i64* %xxy, align 8 %15 = lshr i64 %14, 23 - %16 = and i64 %15, 524287 + %16 = and i64 262143, %15 %17 = trunc i64 %16 to i32 %18 = load i64, i64* %xxy, align 8 %19 = lshr i64 %18, 41 - %20 = and i64 %19, 4194303 + %20 = and i64 2097151, %19 %21 = trunc i64 %20 to i32 call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.3, i32 0, i32 0), i32 %13, i32 %17, i32 %21) - store i64 2292062829969091349, i64* %xxybe, align 8 + store i64 2292133196431502101, i64* %xxybe, align 8 %22 = load i64, i64* %xxybe, align 8 %23 = call i64 @llvm.bswap.i64(i64 %22) %24 = lshr i64 %23, 5 - %25 = and i64 %24, 524287 + %25 = and i64 262143, %24 %26 = trunc i64 %25 to i32 %27 = load i64, i64* %xxybe, align 8 %28 = call i64 @llvm.bswap.i64(i64 %27) %29 = lshr i64 %28, 23 - %30 = and i64 %29, 524287 + %30 = and i64 262143, %29 %31 = trunc i64 %30 to i32 %32 = load i64, i64* %xxybe, align 8 %33 = call i64 @llvm.bswap.i64(i64 %32) %34 = lshr i64 %33, 41 - %35 = and i64 %34, 4194303 + %35 = and i64 2097151, %34 %36 = trunc i64 %35 to i32 call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.4, i32 0, i32 0), i32 %26, i32 %31, i32 %36) ret void -} +} \ No newline at end of file