Fix of ++ and -- on bitstructs.

This commit is contained in:
Christoffer Lerno
2023-08-10 17:52:18 +02:00
parent 6d870fbef0
commit 951a9f2b43
4 changed files with 124 additions and 5 deletions

View File

@@ -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.

View File

@@ -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)

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.602"
#define COMPILER_VERSION "0.4.603"

View File

@@ -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);
}