Support variant.ptr and subarray.ptr

This commit is contained in:
Christoffer Lerno
2021-12-08 16:14:29 +01:00
parent b066c25432
commit b003b05d5d
9 changed files with 174 additions and 32 deletions

View File

@@ -221,6 +221,7 @@ bool expr_is_pure(Expr *expr)
case EXPR_CONST_IDENTIFIER:
case EXPR_IDENTIFIER:
case EXPR_NOP:
case EXPR_PTR:
return true;
case EXPR_BITASSIGN:
return false;

View File

@@ -1539,6 +1539,7 @@ extern Type *type_anyfail;
extern const char *attribute_list[NUMBER_OF_ATTRIBUTES];
extern const char *builtin_list[NUMBER_OF_BUILTINS];
extern const char *kw_std;
extern const char *kw_max;
extern const char *kw_min;
@@ -1562,6 +1563,7 @@ extern const char *kw_reqparse;
extern const char *kw_require;
extern const char *kw_pure;
extern const char *kw_param;
extern const char *kw_ptr;
extern const char *kw_errors;
extern const char *kw___ceil;
extern const char *kw___round;

View File

@@ -127,6 +127,7 @@ Expr *copy_expr(Expr *source_expr)
case EXPR_FAILABLE:
case EXPR_GROUP:
case EXPR_TYPEOFANY:
case EXPR_PTR:
MACRO_COPY_EXPR(expr->inner_expr);
return expr;
case EXPR_COND:

View File

@@ -202,6 +202,7 @@ typedef enum
EXPR_INITIALIZER_LIST,
EXPR_DESIGNATED_INITIALIZER_LIST,
EXPR_LEN,
EXPR_PTR,
EXPR_PLACEHOLDER,
EXPR_POST_UNARY,
EXPR_SCOPED_EXPR,

View File

@@ -1133,14 +1133,14 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
}
break;
case CAST_ANYPTR:
llvm_value_fold_failable(c, value);
llvm_emit_any_pointer(c, value, value);
if (llvm_value_is_addr(value))
{
llvm_emit_any_pointer(c, value, value);
value->value = LLVMBuildBitCast(c->builder, value->value, llvm_get_ptr_type(c, to_type), "");
}
else
{
value->value = LLVMBuildExtractValue(c->builder, value->value, 0, "");
value->value = LLVMBuildBitCast(c->builder, value->value, llvm_get_type(c, to_type), "");
}
break;
case CAST_XIERR:
@@ -1177,15 +1177,7 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
llvm_emit_arr_to_subarray_cast(c, value, to_type);
break;
case CAST_SAPTR:
llvm_value_fold_failable(c, value);
if (llvm_value_is_addr(value))
{
llvm_emit_subarray_pointer(c, value, value);
}
else
{
value->value = LLVMBuildExtractValue(c->builder, value->value, 0, "");
}
llvm_emit_subarray_pointer(c, value, value);
break;
case CAST_ARRPTR:
TODO
@@ -3836,6 +3828,7 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr)
static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values, AlignSize alignment);
static void llvm_expand_array_to_args(GenContext *c, Type *param_type, LLVMValueRef expand_ptr, LLVMValueRef **values, AlignSize alignment)
{
LLVMTypeRef array_type = llvm_get_type(c, param_type);
@@ -3985,30 +3978,33 @@ void llvm_emit_subarray_len(GenContext *c, BEValue *subarray, BEValue *len)
llvm_value_set_address_align(len, len_addr, type_usize, alignment);
}
void llvm_emit_subarray_pointer(GenContext *c, BEValue *subarray, BEValue *pointer)
void llvm_emit_subarray_pointer(GenContext *c, BEValue *value, BEValue *pointer)
{
llvm_value_addr(c, subarray);
AlignSize alignment = 0;
LLVMValueRef pointer_addr = llvm_emit_struct_gep_raw(c,
subarray->value,
llvm_get_type(c, subarray->type),
0,
subarray->alignment,
&alignment);
llvm_value_set_address_align(pointer, pointer_addr, type_get_ptr(subarray->type->array.base), alignment);
assert(value->type->type_kind == TYPE_SUBARRAY);
Type *ptr_type = type_get_ptr(value->type->array.base);
if (value->kind == BE_ADDRESS)
{
AlignSize alignment;
LLVMValueRef ptr = llvm_emit_struct_gep_raw(c, value->value, llvm_get_type(c, value->type), 0, value->alignment, &alignment);
llvm_value_set_address_align(pointer, ptr, ptr_type, alignment);
return;
}
LLVMValueRef ptr = llvm_emit_extract_value(c, value->value, 0);
llvm_value_set(pointer, ptr, ptr_type);
}
static void llvm_emit_any_pointer(GenContext *c, BEValue *any, BEValue *pointer)
static void llvm_emit_any_pointer(GenContext *c, BEValue *value, BEValue *pointer)
{
llvm_value_addr(c, any);
AlignSize alignment = 0;
LLVMValueRef pointer_addr = llvm_emit_struct_gep_raw(c,
any->value,
llvm_get_type(c, type_voidptr),
0,
any->alignment,
&alignment);
llvm_value_set_address_align(pointer, pointer_addr, type_voidptr, alignment);
llvm_value_fold_failable(c, value);
if (value->kind == BE_ADDRESS)
{
AlignSize alignment;
LLVMValueRef ptr = llvm_emit_struct_gep_raw(c, value->value, llvm_get_type(c, value->type), 0, value->alignment, &alignment);
llvm_value_set_address_align(pointer, ptr, type_voidptr, alignment);
return;
}
LLVMValueRef ptr = llvm_emit_extract_value(c, value->value, 0);
llvm_value_set(pointer, ptr, type_voidptr);
}
void llvm_value_struct_gep(GenContext *c, BEValue *element, BEValue *struct_pointer, unsigned index)
@@ -5109,6 +5105,18 @@ void llvm_emit_catch_unwrap(GenContext *c, BEValue *value, Expr *expr)
llvm_value_set(value, addr.value, type_anyerr);
}
static inline void llvm_emit_ptr(GenContext *c, BEValue *value, Expr *expr)
{
llvm_emit_expr(c, value, expr->inner_expr);
if (value->type == type_any)
{
llvm_emit_any_pointer(c, value, value);
return;
}
assert(value->type->type_kind == TYPE_SUBARRAY);
llvm_emit_subarray_pointer(c, value, value);
}
void llvm_emit_try_unwrap_chain(GenContext *c, BEValue *value, Expr *expr)
{
Expr **exprs = expr->try_unwrap_chain_expr;
@@ -5186,6 +5194,9 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
case EXPR_UNDEF:
// Should never reach this.
UNREACHABLE
case EXPR_PTR:
llvm_emit_ptr(c, value, expr);
return;
case EXPR_BUILTIN:
TODO
case EXPR_DECL:
@@ -5291,3 +5302,4 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
UNREACHABLE
}

View File

@@ -819,6 +819,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
case EXPR_TRY_UNWRAP_CHAIN:
case EXPR_SUBSCRIPT_ADDR:
case EXPR_TYPEOFANY:
case EXPR_PTR:
UNREACHABLE
case EXPR_POST_UNARY:
return recursive_may_narrow_float(expr->unary_expr.expr, type);
@@ -971,6 +972,7 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
case EXPR_TRY_UNWRAP_CHAIN:
case EXPR_SUBSCRIPT_ADDR:
case EXPR_TYPEOFANY:
case EXPR_PTR:
UNREACHABLE
case EXPR_POST_UNARY:
return recursive_may_narrow_int(expr->unary_expr.expr, type);

View File

@@ -402,6 +402,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
case EXPR_FORCE_UNWRAP:
case EXPR_TRY:
case EXPR_CATCH:
case EXPR_PTR:
expr = expr->inner_expr;
goto RETRY;
case EXPR_TYPEID:
@@ -2958,6 +2959,27 @@ CHECK_DEEPER:
}
}
// Hard coded ptr on subarrays and variant
if (!is_macro && kw == kw_ptr)
{
if (flat_type->type_kind == TYPE_SUBARRAY)
{
expr->expr_kind = EXPR_PTR;
expr->inner_expr = parent;
expr->type = type_get_ptr(flat_type->array.base);
expr->resolve_status = RESOLVE_DONE;
return true;
}
if (flat_type->type_kind == TYPE_ANY)
{
expr->expr_kind = EXPR_PTR;
expr->inner_expr = parent;
expr->type = type_voidptr;
expr->resolve_status = RESOLVE_DONE;
return true;
}
}
// 9. At this point we may only have distinct, struct, union, error, enum
if (!type_may_have_sub_elements(type))
{
@@ -6655,6 +6677,7 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Expr *expr)
case EXPR_TRY_UNWRAP_CHAIN:
case EXPR_TRY_UNWRAP:
case EXPR_CATCH_UNWRAP:
case EXPR_PTR:
UNREACHABLE
case EXPR_DECL:
if (!sema_analyse_var_decl(context, expr->decl_expr, true)) return false;

View File

@@ -57,6 +57,7 @@ const char *kw_next;
const char *kw_nan;
const char *kw_ordinal;
const char *kw_param;
const char *kw_ptr;
const char *kw_pure;
const char *kw_reqparse;
const char *kw_require;
@@ -136,6 +137,7 @@ void symtab_init(uint32_t capacity)
kw_next = KW_DEF("next");
kw_ordinal = KW_DEF("ordinal");
kw_param = KW_DEF("param");
kw_ptr = KW_DEF("ptr");
kw_pure = KW_DEF("pure");
kw_require = KW_DEF("require");
kw_std = KW_DEF("std");

View File

@@ -0,0 +1,98 @@
// #target: x64-darwin
module foo;
extern fn void printf(char*, ...);
fn void test1(variant z)
{
int* w = z.ptr;
printf("%d\n", *w);
}
fn void test2(int[] z)
{
int* w = z.ptr;
printf("%d\n", *w);
}
fn void main()
{
int x = 123;
int y = 293483;
int[2] w = { 144, 772 };
test1(&x);
test2(w[..]);
}
/* #expect: foo.ll
define void @foo.test1(i64 %0, i8* %1) #0 {
entry:
%z = alloca %variant, align 8
%w = alloca i32*, align 8
%pair = bitcast %variant* %z to { i64, i8* }*
%2 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %pair, i32 0, i32 0
store i64 %0, i64* %2, align 8
%3 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %pair, i32 0, i32 1
store i8* %1, i8** %3, align 8
%4 = getelementptr inbounds %variant, %variant* %z, i32 0, i32 0
%5 = load i8*, i8** %4, align 8
%ptrptr = bitcast i8* %5 to i32*
store i32* %ptrptr, i32** %w, align 8
%6 = load i32*, i32** %w, align 8
%7 = load i32, i32* %6, align 8
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0), i32 %7)
ret void
}
define void @foo.test2(i8* %0, i64 %1) #0 {
entry:
%z = alloca %"int[]", align 8
%w = alloca i32*, align 8
%pair = bitcast %"int[]"* %z to { i8*, i64 }*
%2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 0
store i8* %0, i8** %2, align 8
%3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %pair, i32 0, i32 1
store i64 %1, i64* %3, align 8
%4 = getelementptr inbounds %"int[]", %"int[]"* %z, i32 0, i32 0
%5 = load i32*, i32** %4, align 8
store i32* %5, i32** %w, align 8
%6 = load i32*, i32** %w, align 8
%7 = load i32, i32* %6, align 8
call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i32 %7)
ret void
}
define void @main() #0 {
entry:
%x = alloca i32, align 4
%y = alloca i32, align 4
%w = alloca [2 x i32], align 4
%taddr = alloca %variant, align 8
%taddr1 = alloca %"int[]", align 8
store i32 123, i32* %x, align 4
store i32 293483, i32* %y, align 4
%0 = bitcast [2 x i32]* %w to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast ([2 x i32]* @.__const to i8*), i32 8, i1 false)
%1 = bitcast i32* %x to i8*
%2 = insertvalue %variant undef, i8* %1, 0
%3 = insertvalue %variant %2, i64 5, 1
store %variant %3, %variant* %taddr, align 8
%4 = bitcast %variant* %taddr to { i64, i8* }*
%5 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %4, i32 0, i32 0
%lo = load i64, i64* %5, align 8
%6 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %4, i32 0, i32 1
%hi = load i8*, i8** %6, align 8
call void @foo.test1(i64 %lo, i8* %hi)
%7 = getelementptr inbounds [2 x i32], [2 x i32]* %w, i64 0, i64 0
%8 = insertvalue %"int[]" undef, i32* %7, 0
%9 = insertvalue %"int[]" %8, i64 2, 1
store %"int[]" %9, %"int[]"* %taddr1, align 8
%10 = bitcast %"int[]"* %taddr1 to { i8*, i64 }*
%11 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %10, i32 0, i32 0
%lo2 = load i8*, i8** %11, align 8
%12 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %10, i32 0, i32 1
%hi3 = load i64, i64* %12, align 8
call void @foo.test2(i8* %lo2, i64 %hi3)
ret void
}