From 951a9f2b435c4a21112cd5fceea0b84bcbc0c99e Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Thu, 10 Aug 2023 17:52:18 +0200 Subject: [PATCH] Fix of ++ and -- on bitstructs. --- releasenotes.md | 1 + src/compiler/llvm_codegen_expr.c | 54 +++++++++++++++++-- src/version.h | 2 +- test/unit/regression/bitstruct_ops3.c3 | 72 ++++++++++++++++++++++++++ 4 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 test/unit/regression/bitstruct_ops3.c3 diff --git a/releasenotes.md b/releasenotes.md index b1a70fd9e..10c0bbcb7 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -153,6 +153,7 @@ - Added posix socket functions. ### Fixes +- Fixed ++ and -- for bitstructs. - Fix to bug where library source files were sometimes ignored. - Types of arrays and vectors are consistently checked to be valid. - Anonymous bitstructs check of duplicate member names fixed. diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index c1ea093a7..6d24ada74 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -14,7 +14,7 @@ static inline LLVMValueRef llvm_emit_exprid_to_rvalue(GenContext *c, ExprId expr static inline LLVMValueRef llvm_update_vector(GenContext *c, LLVMValueRef vector, LLVMValueRef value, MemberIndex index); static inline void llvm_emit_expression_list_expr(GenContext *c, BEValue *be_value, Expr *expr); static LLVMValueRef llvm_emit_dynamic_search(GenContext *c, LLVMValueRef type_id_ptr, LLVMValueRef selector); -static inline void llvm_emit_bitassign_array(GenContext *c, BEValue *result, BEValue parent, Decl *parent_decl, Decl *member); +static inline void llvm_emit_bitassign_array(GenContext *c, LLVMValueRef result, BEValue parent, Decl *parent_decl, Decl *member); static inline void llvm_emit_builtin_access(GenContext *c, BEValue *be_value, Expr *expr); static inline void llvm_emit_const_initialize_reference(GenContext *c, BEValue *ref, Expr *expr); static inline void llvm_emit_expr_block(GenContext *context, BEValue *be_value, Expr *expr); @@ -1065,11 +1065,11 @@ static inline void llvm_emit_update_bitstruct_array(GenContext *c, } } -static inline void llvm_emit_bitassign_array(GenContext *c, BEValue *result, BEValue parent, Decl *parent_decl, Decl *member) +static inline void llvm_emit_bitassign_array(GenContext *c, LLVMValueRef result, BEValue parent, Decl *parent_decl, Decl *member) { llvm_value_addr(c, &parent); llvm_emit_update_bitstruct_array(c, parent.value, parent.alignment, llvm_get_type(c, parent.type), - bitstruct_requires_bitswap(parent_decl), member, llvm_load_value_store(c, result)); + bitstruct_requires_bitswap(parent_decl), member, result); } INLINE LLVMValueRef llvm_emit_bitstruct_value_update(GenContext *c, LLVMValueRef current_val, TypeSize bits, LLVMTypeRef bitstruct_type, Decl *member, LLVMValueRef val) @@ -1127,7 +1127,7 @@ static inline void llvm_emit_bitassign_expr(GenContext *c, BEValue *be_value, Ex Type *parent_type = type_flatten(parent_expr->type); if (type_lowering(parent_type)->type_kind == TYPE_ARRAY) { - llvm_emit_bitassign_array(c, be_value, parent, parent_type->decl, member); + llvm_emit_bitassign_array(c, llvm_load_value_store(c, be_value), parent, parent_type->decl, member); return; } @@ -2396,6 +2396,42 @@ static inline bool expr_is_vector_subscript(Expr *expr) return type->type_kind == TYPE_VECTOR; } +/** + * This method implements the common ++x and --x operators on bitstructs + */ +static inline void llvm_emit_pre_post_inc_dec_bitstruct(GenContext *c, BEValue *be_value, Expr *lhs, int diff, bool pre) +{ + Expr *parent_expr = lhs->access_expr.parent; + + // Grab the parent + 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); + + BEValue value = parent; + llvm_extract_bitvalue(c, &value, parent_expr, 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) + { + llvm_emit_bitassign_array(c, result, parent, parent_type->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); + 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); + if (bswap) current_value = llvm_emit_bswap(c, current_value); + llvm_store_raw(c, &parent, current_value); +} + /** * This method implements the common ++x and --x operators on vector elements */ @@ -2451,6 +2487,11 @@ static inline void llvm_emit_pre_inc_dec(GenContext *c, BEValue *value, Expr *ex llvm_emit_pre_post_inc_dec_vector(c, value, expr, diff, true); return; } + if (expr->expr_kind == EXPR_BITACCESS) + { + llvm_emit_pre_post_inc_dec_bitstruct(c, value, expr, diff, true); + return; + } // Pull out the address, also allowing temporaries. BEValue addr; llvm_emit_expr(c, &addr, expr); @@ -2504,6 +2545,11 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e llvm_emit_pre_post_inc_dec_vector(c, value, expr, diff, false); return; } + if (expr->expr_kind == EXPR_BITACCESS) + { + llvm_emit_pre_post_inc_dec_bitstruct(c, value, expr, diff, false); + return; + } // Retrieve the address, creating a temp in case this is // a temporary value (this gives us a lot of flexibility for temporaries) diff --git a/src/version.h b/src/version.h index d6b603ef9..ae6dfc6a5 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.602" \ No newline at end of file +#define COMPILER_VERSION "0.4.603" \ No newline at end of file diff --git a/test/unit/regression/bitstruct_ops3.c3 b/test/unit/regression/bitstruct_ops3.c3 new file mode 100644 index 000000000..fe4122b87 --- /dev/null +++ b/test/unit/regression/bitstruct_ops3.c3 @@ -0,0 +1,72 @@ +module bitstruct_ops_inc @test; +import std::io; + +struct Data { + bitstruct : ushort @overlap { + char a : 0..7; + } + bitstruct : ushort @overlap { + ushort ab : 0..15; + } +} + +bitstruct Foo : char[10] +{ + int a : 10..15; +} + +struct NewData { + char a; + ushort ab; +} + +fn void test_inc() +{ + NewData newdata; + newdata.a = 0x55; + newdata.ab = 0xAABB; + NewData newdata2 = newdata; + + newdata.a += 1; + newdata.ab += 1; + newdata2.a++; + newdata2.ab++; + assert(newdata.a == newdata2.a, "Structs: Expected %x, found %x", newdata.a, newdata2.a); + assert(newdata.ab == newdata2.ab, "Structs: Expected %x, found %x", newdata.ab, newdata2.ab); + + Data data; + data.a = 0x55; + data.ab = 0xAABB; + Data data2 = data; + + data.a += 1; + data.ab += 1; + data2.a++; + data2.ab++; + assert(data.a == data2.a, "BitStructs: Expected %x, found %x", data.a, data2.a); + assert(data.ab == data2.ab, "BitStructs: Expected %x, found %x", data.ab, data2.ab); + + data.a -= 1; + data.ab -= 1; + data2.a--; + data2.ab--; + assert(data.a == data2.a, "BitStructs: Expected %x, found %x", data.a, data2.a); + assert(data.ab == data2.ab, "BitStructs: Expected %x, found %x", data.ab, data2.ab); + + char a = data.a; + assert(a == data.a++); + assert(a != data.a); + assert(a == --data.a); + +} + + +fn void test_inc_array() +{ + Foo x; + x.a = 10; + assert(x.a == 10); + assert(x.a++ == 10); + assert(x.a == 11, "Value was %d", x.a); + assert(--x.a == 10); +} \ No newline at end of file