Remove all array pointer decay.

This commit is contained in:
Christoffer Lerno
2023-03-02 19:47:24 +01:00
parent 3372f36e9d
commit 3449d2ea88
7 changed files with 120 additions and 68 deletions

View File

@@ -237,6 +237,7 @@ static bool voidfail_to_error(Expr *expr, Type *type)
return true;
}
/**
* Cast int to bool using CAST_INTBOOL
* or rewrite 0 => false, any other value => true
@@ -466,18 +467,56 @@ static bool array_to_vector(Expr *expr, Type *to_type)
/**
* We have two cases:
* 1. int[] -> Foo[] where Foo is a distinct or typedef OR it is a constant. Then we can just redefine
* 2. The second case is something like int*[] -> void*[] for this case we need to make a bitcast.
* 2. The second case is something like int*[] -> void*[] for this case we need to make a bitcast using CAST_SASA.
*/
INLINE bool subarray_to_subarray(Expr *expr, Type *to_type)
{
if (expr_is_const(expr) || type_flatten(type_flatten(to_type)->array.base) == type_flatten(type_flatten(expr->type)->array.base))
{
// Here we assume int[] -> float[] can't happen.
expr->type = to_type;
return true;
}
return insert_cast(expr, CAST_SASA, to_type);
}
/**
* Bitstruct casts go from its base type to any integer or char array of the same size.
*/
static bool bitstruct_cast(Expr *expr, Type *bitstruct_type, Type *to, Type *to_type)
{
assert(type_size(to) == type_size(bitstruct_type) && "Only casts to the same width expected.");
// The case where the bitstruct is backed by an integer
if (type_is_integer(bitstruct_type))
{
// The same size integer, this is the simple case.
if (type_is_integer(to))
{
expr->type = to_type;
return true;
}
// Now we expect a char array of the same size. This
// is runtime only.
assert(to->type_kind == TYPE_ARRAY);
return insert_cast(expr, CAST_BSARRY, to_type);
}
// Converting from a char array.
assert(bitstruct_type->type_kind == TYPE_ARRAY);
// Converting to a char array is the simple case, just change the type.
if (to->type_kind == TYPE_ARRAY)
{
expr->type = to_type;
return true;
}
// Converting to an integer, this is a runtime cast.
assert(type_is_integer(to));
return insert_cast(expr, CAST_BSINT, to_type);
}
/**
* Cast using CAST_VECARR, casting an array to a vector. For the constant, this
* is a simple type change, see array_to_vector.
@@ -568,6 +607,39 @@ bool cast_promote_vararg(Expr *arg)
return true;
}
/**
* Given lhs and rhs, promote to the maximum bit size, this will retain
* signed/unsigned type of each side.
*/
void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type)
{
unsigned bit_size_left = left_type->builtin.bitsize;
unsigned bit_size_right = right_type->builtin.bitsize;
assert(bit_size_left && bit_size_right);
// Simple case they are the same size, just return.
if (bit_size_left == bit_size_right) return;
// Lhs is smaller than rhs, so widen it using the right type
if (bit_size_left < bit_size_right)
{
Type *to = lhs->type->type_kind < TYPE_U8
? type_int_signed_by_bitsize(bit_size_right)
: type_int_unsigned_by_bitsize(bit_size_right);
bool success = cast(lhs, to);
assert(success);
return;
}
// Rhs is smaller, do the same thing as above but with the rhs.
Type *to = rhs->type->type_kind < TYPE_U8
? type_int_signed_by_bitsize(bit_size_left)
: type_int_unsigned_by_bitsize(bit_size_left);
bool success = cast(rhs, to);
assert(success);
}
/**
* For implicit casts to bool, in a conditional, return the type of cast to
* insert.
@@ -1931,7 +2003,7 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type)
case CT_TYPES:
UNREACHABLE
case TYPE_BITSTRUCT:
return bitstruct_cast(expr, from_type, to, to_type);
return bitstruct_cast(expr, type_flatten(from_type->decl->bitstruct.base_type->type), to, to_type);
case TYPE_BOOL:
// Bool may convert into integers and floats but only explicitly.
if (type_is_integer(to)) return bool_to_int(expr, to, to_type);
@@ -2019,28 +2091,6 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type)
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)
{
@@ -2173,37 +2223,7 @@ Type *cast_numeric_arithmetic_promotion(Type *type)
}
}
bool cast_decay_array_pointers(SemaContext *context, Expr *expr)
{
CanonicalType *pointer_type = type_pointer_type(type_no_optional(expr->type));
if (!pointer_type || !type_is_arraylike(pointer_type)) return true;
return cast_expr_inner(context,
expr,
type_add_optional(type_get_ptr(pointer_type->array.base), IS_OPTIONAL(expr)),
true, false, false);
}
void cast_to_max_bit_size(SemaContext *context, Expr *left, Expr *right, Type *left_type, Type *right_type)
{
unsigned bit_size_left = left_type->builtin.bitsize;
unsigned bit_size_right = right_type->builtin.bitsize;
assert(bit_size_left && bit_size_right);
if (bit_size_left == bit_size_right) return;
if (bit_size_left < bit_size_right)
{
Type *to = left->type->type_kind < TYPE_U8
? type_int_signed_by_bitsize(bit_size_right)
: type_int_unsigned_by_bitsize(bit_size_right);
bool success = cast(left, to);
assert(success);
return;
}
Type *to = right->type->type_kind < TYPE_U8
? type_int_signed_by_bitsize(bit_size_left)
: type_int_unsigned_by_bitsize(bit_size_left);
bool success = cast(right, to);
assert(success);
}
#pragma clang diagnostic pop

View File

@@ -4324,7 +4324,6 @@ static bool sema_expr_analyse_add_sub_assign(SemaContext *context, Expr *expr, E
if (left_type_canonical->type_kind == TYPE_POINTER)
{
if (!cast_decay_array_pointers(context, left)) return false;
expr->type = left->type;
// 7. Finally, check that the right side is indeed an integer.
@@ -4423,13 +4422,11 @@ static bool sema_expr_analyse_sub(SemaContext *context, Expr *expr, Expr *left,
// 2. Handle the ptr - x and ptr - other_pointer
if (left_type->type_kind == TYPE_POINTER)
{
if (!cast_decay_array_pointers(context, left)) return false;
left_type = type_no_optional(left->type)->canonical;
// 3. ptr - other pointer
if (right_type->type_kind == TYPE_POINTER)
{
if (!cast_decay_array_pointers(context, right)) return false;
right_type = type_no_optional(right->type)->canonical;
// 3a. Require that both types are the same.
@@ -4580,8 +4577,6 @@ static bool sema_expr_analyse_add(SemaContext *context, Expr *expr, Expr *left,
// so check if we want to do the normal pointer add special handling.
if (left_type->type_kind == TYPE_POINTER)
{
if (!cast_decay_array_pointers(context, left)) return false;
// 3a. Check that the other side is an integer of some sort.
if (!type_is_integer(right_type))
{
@@ -5076,7 +5071,7 @@ static bool sema_expr_analyse_comp(SemaContext *context, Expr *expr, Expr *left,
|| (type_is_signed(left_type) && type_is_unsigned(right_type)))
{
// 2a. Resize so that both sides have the same bit width. This will always work.
cast_to_max_bit_size(context, left, right, left_type, right_type);
cast_to_int_to_max_bit_size(context, left, right, left_type, right_type);
goto DONE;
}
@@ -5580,8 +5575,6 @@ static inline bool sema_expr_analyse_incdec(SemaContext *context, Expr *expr)
return false;
}
if (!cast_decay_array_pointers(context, inner)) return false;
// 6. Done, the result is same as the inner type.
expr->type = inner->type;
return true;

View File

@@ -83,8 +83,8 @@ Type *sema_analyse_function_signature(SemaContext *context, Decl *parent, CallAB
bool cast_widen_top_down(SemaContext *context, Expr *expr, Type *type);
bool cast_promote_vararg(Expr *arg);
Type *cast_numeric_arithmetic_promotion(Type *type);
void cast_to_max_bit_size(SemaContext *context, Expr *left, Expr *right, Type *left_type, Type *right_type);
bool cast_decay_array_pointers(SemaContext *context, Expr *expr);
void cast_to_int_to_max_bit_size(SemaContext *context, Expr *lhs, Expr *rhs, Type *left_type, Type *right_type);
INLINE bool sema_set_abi_alignment(SemaContext *context, Type *type, AlignSize *result);
INLINE bool sema_set_alloca_alignment(SemaContext *context, Type *type, AlignSize *result);
void sema_display_deprecated_warning_on_use(SemaContext *context, Decl *decl, SourceSpan use);

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.92"
#define COMPILER_VERSION "0.4.93"

View File

@@ -0,0 +1,20 @@
// #target: macos-x64
module test;
bitstruct Foo : int
{
int abc : 0..4;
int def : 23..26;
}
fn void main()
{
Foo f;
int z = (int) Foo { .abc = 2, .def = 1 };
}
/* #expect: test.ll
%f = alloca i32, align 4
%z = alloca i32, align 4
store i32 0, ptr %f, align 4
store i32 8388610, ptr %z, align 4

View File

@@ -13,7 +13,7 @@ fn void main()
int* xx = &x + 1;
int[3]* yy = (int[3]*)(xx);
int* zz = yy - 1;
printf("%p = %p = %p, %p = %p\n", y, z, zz, &(*y)[1], xx);
printf("%p = %p = %p, %p != %p\n", y, z, zz, &(*y)[1], xx);
x[1] = 123;
printf("%d = %d\n", x[1], z[1]);
}
@@ -52,12 +52,12 @@ entry:
%ptroffset1 = getelementptr inbounds i32, ptr %8, i64 1
%9 = load i32, ptr %ptroffset1, align 4
store i32 %9, ptr %z1, align 4
%ptroffset2 = getelementptr i32, ptr %x, i64 1
%ptroffset2 = getelementptr [3 x i32], ptr %x, i64 1
store ptr %ptroffset2, ptr %xx, align 8
%10 = load ptr, ptr %xx, align 8
store ptr %10, ptr %yy, align 8
%11 = load ptr, ptr %yy, align 8
%ptroffset3 = getelementptr i32, ptr %11, i64 -1
%ptroffset3 = getelementptr [3 x i32], ptr %11, i64 -1
store ptr %ptroffset3, ptr %zz, align 8
%12 = load ptr, ptr %y, align 8
%13 = load ptr, ptr %z, align 8

View File

@@ -0,0 +1,19 @@
module test @test;
fn void pointer_non_decay()
{
int[3] x;
int[3]* y = &x;
int* z = y;
int[] sub = y;
int[3] y1 = y[1];
int z1 = z[1];
int* xx = &x + 1;
int[3]* yy = (int[3]*)(xx);
int* zz = yy - 1;
assert(y == z);
assert(z == zz);
assert(&(*y)[1] == &xx[-2]);
x[1] = 123;
assert(x[1] == z[1]);
}