mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Support variant.ptr and subarray.ptr
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
98
test/test_suite/pointers/subarray_variant_to_ptr.c3t
Normal file
98
test/test_suite/pointers/subarray_variant_to_ptr.c3t
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user