mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fixes to bitstruct and work on correct behaviour when embedded in structs.
This commit is contained in:
committed by
Christoffer Lerno
parent
4f09b0c351
commit
4e47f0b624
@@ -82,6 +82,8 @@ typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CAST_BSARRY,
|
||||
CAST_BSINT,
|
||||
CAST_ERROR,
|
||||
CAST_ERBOOL,
|
||||
CAST_EUBOOL,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
63
test/test_suite/bitstruct/bitstruct_init.c3
Normal file
63
test/test_suite/bitstruct/bitstruct_init.c3
Normal file
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user